00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "nodePath.h"
00020 #include "nodePathCollection.h"
00021 #include "findApproxPath.h"
00022 #include "findApproxLevelEntry.h"
00023 #include "findApproxLevel.h"
00024 #include "config_pgraph.h"
00025 #include "colorAttrib.h"
00026 #include "colorScaleAttrib.h"
00027 #include "cullBinAttrib.h"
00028 #include "textureAttrib.h"
00029 #include "materialAttrib.h"
00030 #include "fogAttrib.h"
00031 #include "renderModeAttrib.h"
00032 #include "cullFaceAttrib.h"
00033 #include "alphaTestAttrib.h"
00034 #include "depthTestAttrib.h"
00035 #include "depthWriteAttrib.h"
00036 #include "billboardEffect.h"
00037 #include "compassEffect.h"
00038 #include "showBoundsEffect.h"
00039 #include "transparencyAttrib.h"
00040 #include "materialPool.h"
00041 #include "look_at.h"
00042 #include "compose_matrix.h"
00043 #include "plist.h"
00044 #include "boundingSphere.h"
00045 #include "geomNode.h"
00046 #include "sceneGraphReducer.h"
00047 #include "textureCollection.h"
00048 #include "globPattern.h"
00049 #include "config_gobj.h"
00050 #include "bamFile.h"
00051 #include "dcast.h"
00052
00053
00054
00055 int NodePath::_max_search_depth = 7000;
00056 TypeHandle NodePath::_type_handle;
00057
00058
00059
00060
00061
00062
00063 int NodePath::
00064 get_num_nodes() const {
00065 if (is_empty()) {
00066 return 0;
00067 }
00068 uncollapse_head();
00069 return _head->get_length();
00070 }
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 PandaNode *NodePath::
00081 get_node(int index) const {
00082 nassertr(index >= 0 && index < get_num_nodes(), NULL);
00083
00084 uncollapse_head();
00085 NodePathComponent *comp = _head;
00086 while (index > 0) {
00087
00088
00089 nassertr(comp != (NodePathComponent *)NULL, NULL);
00090 comp = comp->get_next();
00091 index--;
00092 }
00093
00094
00095
00096 nassertr(comp != (NodePathComponent *)NULL, NULL);
00097 return comp->get_node();
00098 }
00099
00100
00101
00102
00103
00104
00105
00106 PandaNode *NodePath::
00107 get_top_node() const {
00108 if (is_empty()) {
00109 return (PandaNode *)NULL;
00110 }
00111
00112 uncollapse_head();
00113 NodePathComponent *comp = _head;
00114 while (!comp->is_top_node()) {
00115 comp = comp->get_next();
00116 nassertr(comp != (NodePathComponent *)NULL, NULL);
00117 }
00118
00119 return comp->get_node();
00120 }
00121
00122
00123
00124
00125
00126
00127
00128
00129 NodePathCollection NodePath::
00130 get_children() const {
00131 NodePathCollection result;
00132 nassertr_always(!is_empty(), result);
00133
00134 PandaNode *bottom_node = node();
00135
00136 PandaNode::Children cr = bottom_node->get_children();
00137 int num_children = cr.get_num_children();
00138 for (int i = 0; i < num_children; i++) {
00139 NodePath child;
00140 child._head = PandaNode::get_component(_head, cr.get_child(i));
00141 result.add_path(child);
00142 }
00143
00144 return result;
00145 }
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 NodePath NodePath::
00156 find(const string &path) const {
00157 nassertr_always(!is_empty(), fail());
00158
00159 NodePathCollection col;
00160 find_matches(col, path, 1);
00161
00162 if (col.is_empty()) {
00163 return NodePath::not_found();
00164 }
00165
00166 return col.get_path(0);
00167 }
00168
00169
00170
00171
00172
00173
00174
00175 NodePath NodePath::
00176 find_path_to(PandaNode *node) const {
00177 nassertr_always(!is_empty(), fail());
00178 nassertr(node != (PandaNode *)NULL, fail());
00179
00180 NodePathCollection col;
00181 FindApproxPath approx_path;
00182 approx_path.add_match_many(0);
00183 approx_path.add_match_pointer(node, 0);
00184 find_matches(col, approx_path, 1);
00185
00186 if (col.is_empty()) {
00187 return NodePath::not_found();
00188 }
00189
00190 return col.get_path(0);
00191 }
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 NodePathCollection NodePath::
00202 find_all_matches(const string &path) const {
00203 NodePathCollection col;
00204 nassertr_always(!is_empty(), col);
00205 nassertr(verify_complete(), col);
00206 find_matches(col, path, -1);
00207 return col;
00208 }
00209
00210
00211
00212
00213
00214
00215
00216
00217 NodePathCollection NodePath::
00218 find_all_paths_to(PandaNode *node) const {
00219 NodePathCollection col;
00220 nassertr_always(!is_empty(), col);
00221 nassertr(verify_complete(), col);
00222 nassertr(node != (PandaNode *)NULL, col);
00223 FindApproxPath approx_path;
00224 approx_path.add_match_many(0);
00225 approx_path.add_match_pointer(node, 0);
00226 find_matches(col, approx_path, -1);
00227 return col;
00228 }
00229
00230
00231
00232
00233
00234
00235
00236
00237 void NodePath::
00238 reparent_to(const NodePath &other, int sort) {
00239 nassertv(verify_complete());
00240 nassertv(other.verify_complete());
00241 nassertv_always(!is_empty());
00242 nassertv_always(!other.is_empty());
00243
00244 uncollapse_head();
00245 other.uncollapse_head();
00246 PandaNode::reparent(other._head, _head, sort);
00247 }
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258 void NodePath::
00259 wrt_reparent_to(const NodePath &other, int sort) {
00260 nassertv(verify_complete());
00261 nassertv(other.verify_complete());
00262 nassertv_always(!is_empty());
00263 nassertv_always(!other.is_empty());
00264
00265 set_transform(get_transform(other));
00266 reparent_to(other, sort);
00267 }
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286 NodePath NodePath::
00287 instance_to(const NodePath &other, int sort) const {
00288 nassertr(verify_complete(), NodePath::fail());
00289 nassertr(other.verify_complete(), NodePath::fail());
00290 nassertr_always(!is_empty(), NodePath::fail());
00291 nassertr(!other.is_empty(), NodePath::fail());
00292
00293 uncollapse_head();
00294 other.uncollapse_head();
00295
00296 NodePath new_instance;
00297 new_instance._head = PandaNode::attach(other._head, node(), sort);
00298
00299 return new_instance;
00300 }
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 NodePath NodePath::
00312 instance_under_node(const NodePath &other, const string &name, int sort) const {
00313 NodePath new_node = other.attach_new_node(name, sort);
00314 NodePath instance = instance_to(new_node);
00315 if (instance.is_empty()) {
00316 new_node.remove_node();
00317 return instance;
00318 }
00319 return new_node;
00320 }
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331 NodePath NodePath::
00332 copy_to(const NodePath &other, int sort) const {
00333 nassertr(verify_complete(), fail());
00334 nassertr(other.verify_complete(), fail());
00335 nassertr_always(!is_empty(), fail());
00336 nassertr(!other.is_empty(), fail());
00337
00338 PandaNode *source_node = node();
00339 PT(PandaNode) copy_node = source_node->copy_subgraph();
00340 nassertr(copy_node != (PandaNode *)NULL, fail());
00341
00342 return other.attach_new_node(copy_node, sort);
00343 }
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358 NodePath NodePath::
00359 attach_new_node(PandaNode *node, int sort) const {
00360 nassertr(verify_complete(), NodePath::fail());
00361 nassertr_always(!is_empty(), NodePath());
00362 nassertr(node != (PandaNode *)NULL, NodePath());
00363
00364 uncollapse_head();
00365 NodePath new_path(*this);
00366 new_path._head = PandaNode::attach(_head, node, sort);
00367 return new_path;
00368 }
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386 void NodePath::
00387 remove_node() {
00388 nassertv(_error_type != ET_not_found);
00389
00390
00391
00392
00393
00394 if (!is_empty() && !is_singleton()) {
00395 uncollapse_head();
00396 PandaNode::detach(_head);
00397 }
00398
00399 (*this) = NodePath::removed();
00400 }
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 void NodePath::
00417 detach_node() {
00418 nassertv(_error_type != ET_not_found);
00419 if (!is_empty() && !is_singleton()) {
00420 uncollapse_head();
00421 PandaNode::detach(_head);
00422 }
00423 }
00424
00425
00426
00427
00428
00429
00430
00431 void NodePath::
00432 output(ostream &out) const {
00433 uncollapse_head();
00434
00435 switch (_error_type) {
00436 case ET_not_found:
00437 out << "**not found**";
00438 return;
00439 case ET_removed:
00440 out << "**removed**";
00441 return;
00442 case ET_fail:
00443 out << "**error**";
00444 return;
00445 default:
00446 break;
00447 }
00448
00449 if (_head == (NodePathComponent *)NULL) {
00450 out << "(empty)";
00451 } else {
00452 _head->output(out);
00453 }
00454 }
00455
00456
00457
00458
00459
00460
00461
00462
00463 CPT(RenderState) NodePath::
00464 get_state(const NodePath &other) const {
00465 if (is_empty()) {
00466 return other.get_net_state();
00467 }
00468 if (other.is_empty()) {
00469 return get_net_state()->invert_compose(RenderState::make_empty());
00470 }
00471
00472 nassertr(verify_complete(), RenderState::make_empty());
00473 nassertr(other.verify_complete(), RenderState::make_empty());
00474
00475 int a_count, b_count;
00476 find_common_ancestor(*this, other, a_count, b_count);
00477
00478 CPT(RenderState) a_state = r_get_partial_state(_head, a_count);
00479 CPT(RenderState) b_state = r_get_partial_state(other._head, b_count);
00480 return a_state->invert_compose(b_state);
00481 }
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491 void NodePath::
00492 set_state(const NodePath &other, const RenderState *state) const {
00493 nassertv(_error_type == ET_ok && other._error_type == ET_ok);
00494 nassertv_always(!is_empty());
00495
00496
00497 NodePath parent = get_parent();
00498 CPT(RenderState) rel_state = parent.get_state(other);
00499
00500 CPT(RenderState) new_state = rel_state->compose(state);
00501 set_state(new_state);
00502 }
00503
00504
00505
00506
00507
00508
00509
00510
00511 CPT(TransformState) NodePath::
00512 get_transform(const NodePath &other) const {
00513 if (other.is_empty()) {
00514 return get_net_transform();
00515 }
00516 if (is_empty()) {
00517 return other.get_net_transform()->invert_compose(TransformState::make_identity());
00518 }
00519
00520 nassertr(verify_complete(), TransformState::make_identity());
00521 nassertr(other.verify_complete(), TransformState::make_identity());
00522
00523 int a_count, b_count;
00524 find_common_ancestor(*this, other, a_count, b_count);
00525
00526 CPT(TransformState) a_transform = r_get_partial_transform(_head, a_count);
00527 CPT(TransformState) b_transform = r_get_partial_transform(other._head, b_count);
00528 return b_transform->invert_compose(a_transform);
00529 }
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539 void NodePath::
00540 set_transform(const NodePath &other, const TransformState *transform) const {
00541 nassertv(_error_type == ET_ok && other._error_type == ET_ok);
00542 nassertv_always(!is_empty());
00543
00544
00545 CPT(TransformState) rel_trans;
00546 if (has_parent()) {
00547 rel_trans = other.get_transform(get_parent());
00548 } else {
00549 rel_trans = other.get_transform(NodePath());
00550 }
00551
00552 CPT(TransformState) new_trans = rel_trans->compose(transform);
00553 set_transform(new_trans);
00554 }
00555
00556
00557
00558
00559
00560
00561
00562 void NodePath::
00563 set_pos(const LVecBase3f &pos) {
00564 nassertv_always(!is_empty());
00565 set_transform(get_transform()->set_pos(pos));
00566 }
00567
00568 void NodePath::
00569 set_x(float x) {
00570 nassertv_always(!is_empty());
00571 LPoint3f pos = get_pos();
00572 pos[0] = x;
00573 set_pos(pos);
00574 }
00575
00576 void NodePath::
00577 set_y(float y) {
00578 nassertv_always(!is_empty());
00579 LPoint3f pos = get_pos();
00580 pos[1] = y;
00581 set_pos(pos);
00582 }
00583
00584 void NodePath::
00585 set_z(float z) {
00586 nassertv_always(!is_empty());
00587 LPoint3f pos = get_pos();
00588 pos[2] = z;
00589 set_pos(pos);
00590 }
00591
00592
00593
00594
00595
00596
00597 LPoint3f NodePath::
00598 get_pos() const {
00599 nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
00600 return get_transform()->get_pos();
00601 }
00602
00603
00604
00605
00606
00607
00608
00609 void NodePath::
00610 set_hpr(const LVecBase3f &hpr) {
00611 nassertv_always(!is_empty());
00612 CPT(TransformState) transform = get_transform();
00613 nassertv(transform->has_hpr());
00614 set_transform(transform->set_hpr(hpr));
00615 }
00616
00617 void NodePath::
00618 set_h(float h) {
00619 nassertv_always(!is_empty());
00620 CPT(TransformState) transform = get_transform();
00621 nassertv(transform->has_hpr());
00622 LVecBase3f hpr = transform->get_hpr();
00623 hpr[0] = h;
00624 set_transform(transform->set_hpr(hpr));
00625 }
00626
00627 void NodePath::
00628 set_p(float p) {
00629 nassertv_always(!is_empty());
00630 CPT(TransformState) transform = get_transform();
00631 nassertv(transform->has_hpr());
00632 LVecBase3f hpr = transform->get_hpr();
00633 hpr[1] = p;
00634 set_transform(transform->set_hpr(hpr));
00635 }
00636
00637 void NodePath::
00638 set_r(float r) {
00639 nassertv_always(!is_empty());
00640 CPT(TransformState) transform = get_transform();
00641 nassertv(transform->has_hpr());
00642 LVecBase3f hpr = transform->get_hpr();
00643 hpr[2] = r;
00644 set_transform(transform->set_hpr(hpr));
00645 }
00646
00647
00648
00649
00650
00651
00652 LVecBase3f NodePath::
00653 get_hpr() const {
00654 nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f));
00655 CPT(TransformState) transform = get_transform();
00656 nassertr(transform->has_hpr(), LVecBase3f(0.0f, 0.0f, 0.0f));
00657 return transform->get_hpr();
00658 }
00659
00660
00661
00662
00663
00664
00665 LVecBase3f NodePath::
00666 get_hpr(float roll) const {
00667
00668
00669
00670 return get_hpr();
00671 }
00672
00673
00674
00675
00676
00677
00678
00679 void NodePath::
00680 set_quat(const LQuaternionf &quat) {
00681 nassertv_always(!is_empty());
00682 CPT(TransformState) transform = get_transform();
00683 set_transform(transform->set_quat(quat));
00684 }
00685
00686
00687
00688
00689
00690
00691 LQuaternionf NodePath::
00692 get_quat() const {
00693 nassertr_always(!is_empty(), LQuaternionf::ident_quat());
00694 CPT(TransformState) transform = get_transform();
00695 return transform->get_quat();
00696 }
00697
00698
00699
00700
00701
00702
00703
00704 void NodePath::
00705 set_scale(const LVecBase3f &scale) {
00706 nassertv_always(!is_empty());
00707 CPT(TransformState) transform = get_transform();
00708 set_transform(transform->set_scale(scale));
00709 }
00710
00711 void NodePath::
00712 set_sx(float sx) {
00713 nassertv_always(!is_empty());
00714 CPT(TransformState) transform = get_transform();
00715 LVecBase3f scale = transform->get_scale();
00716 scale[0] = sx;
00717 set_transform(transform->set_scale(scale));
00718 }
00719
00720 void NodePath::
00721 set_sy(float sy) {
00722 nassertv_always(!is_empty());
00723 CPT(TransformState) transform = get_transform();
00724 LVecBase3f scale = transform->get_scale();
00725 scale[1] = sy;
00726 set_transform(transform->set_scale(scale));
00727 }
00728
00729 void NodePath::
00730 set_sz(float sz) {
00731 nassertv_always(!is_empty());
00732 CPT(TransformState) transform = get_transform();
00733 LVecBase3f scale = transform->get_scale();
00734 scale[2] = sz;
00735 set_transform(transform->set_scale(scale));
00736 }
00737
00738
00739
00740
00741
00742
00743 LVecBase3f NodePath::
00744 get_scale() const {
00745 nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f));
00746 CPT(TransformState) transform = get_transform();
00747 return transform->get_scale();
00748 }
00749
00750
00751
00752
00753
00754
00755
00756 void NodePath::
00757 set_pos_hpr(const LVecBase3f &pos, const LVecBase3f &hpr) {
00758 nassertv_always(!is_empty());
00759 CPT(TransformState) transform = get_transform();
00760 transform = TransformState::make_pos_hpr_scale
00761 (pos, hpr, transform->get_scale());
00762 set_transform(transform);
00763 }
00764
00765
00766
00767
00768
00769
00770
00771 void NodePath::
00772 set_hpr_scale(const LVecBase3f &hpr, const LVecBase3f &scale) {
00773 nassertv_always(!is_empty());
00774 CPT(TransformState) transform = get_transform();
00775 transform = TransformState::make_pos_hpr_scale
00776 (transform->get_pos(), hpr, scale);
00777 set_transform(transform);
00778 }
00779
00780
00781
00782
00783
00784
00785
00786 void NodePath::
00787 set_pos_hpr_scale(const LVecBase3f &pos, const LVecBase3f &hpr,
00788 const LVecBase3f &scale) {
00789 nassertv_always(!is_empty());
00790 set_transform(TransformState::make_pos_hpr_scale
00791 (pos, hpr, scale));
00792 }
00793
00794
00795
00796
00797
00798
00799
00800 void NodePath::
00801 set_pos_quat_scale(const LVecBase3f &pos, const LQuaternionf &quat,
00802 const LVecBase3f &scale) {
00803 nassertv_always(!is_empty());
00804 set_transform(TransformState::make_pos_quat_scale
00805 (pos, quat, scale));
00806 }
00807
00808
00809
00810
00811
00812
00813 void NodePath::
00814 set_mat(const LMatrix4f &mat) {
00815 nassertv_always(!is_empty());
00816 set_transform(TransformState::make_mat(mat));
00817 }
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827 bool NodePath::
00828 has_color_scale() const {
00829 nassertr_always(!is_empty(), false);
00830 return node()->has_attrib(ColorScaleAttrib::get_class_type());
00831 }
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842 void NodePath::
00843 clear_color_scale() {
00844 nassertv_always(!is_empty());
00845 node()->clear_attrib(ColorScaleAttrib::get_class_type());
00846 }
00847
00848
00849
00850
00851
00852
00853
00854 void NodePath::
00855 set_color_scale(const LVecBase4f &scale) {
00856 nassertv_always(!is_empty());
00857 node()->set_attrib(ColorScaleAttrib::make(scale));
00858 }
00859
00860
00861
00862
00863
00864
00865
00866
00867 const LVecBase4f &NodePath::
00868 get_color_scale() const {
00869 static const LVecBase4f ident_scale(1.0f, 1.0f, 1.0f, 1.0f);
00870 nassertr_always(!is_empty(), ident_scale);
00871 const RenderAttrib *attrib =
00872 node()->get_attrib(ColorScaleAttrib::get_class_type());
00873 if (attrib != (const RenderAttrib *)NULL) {
00874 const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
00875 return csa->get_scale();
00876 }
00877
00878 return ident_scale;
00879 }
00880
00881
00882
00883
00884
00885
00886
00887 void NodePath::
00888 look_at(const LPoint3f &point, const LVector3f &up) {
00889 nassertv_always(!is_empty());
00890
00891 LPoint3f pos = get_pos();
00892
00893 LQuaternionf quat;
00894 ::look_at(quat, point - pos, up);
00895 set_quat(quat);
00896 }
00897
00898
00899
00900
00901
00902
00903
00904
00905 void NodePath::
00906 heads_up(const LPoint3f &point, const LVector3f &up) {
00907 nassertv_always(!is_empty());
00908
00909 LPoint3f pos = get_pos();
00910
00911 LQuaternionf quat;
00912 ::heads_up(quat, point - pos, up);
00913 set_quat(quat);
00914 }
00915
00916
00917
00918
00919
00920
00921
00922 void NodePath::
00923 set_pos(const NodePath &other, const LVecBase3f &pos) {
00924 nassertv_always(!is_empty());
00925 CPT(TransformState) rel_transform = get_transform(other);
00926
00927 CPT(TransformState) orig_transform = get_transform();
00928 if (orig_transform->has_components()) {
00929
00930
00931
00932
00933 const LVecBase3f &orig_hpr = orig_transform->get_hpr();
00934 const LVecBase3f &orig_scale = orig_transform->get_scale();
00935
00936 set_transform(other, rel_transform->set_pos(pos));
00937 set_pos_hpr_scale(get_transform()->get_pos(), orig_hpr, orig_scale);
00938
00939 } else {
00940
00941
00942 set_transform(other, rel_transform->set_pos(pos));
00943 }
00944 }
00945
00946 void NodePath::
00947 set_x(const NodePath &other, float x) {
00948 nassertv_always(!is_empty());
00949 LPoint3f pos = get_pos(other);
00950 pos[0] = x;
00951 set_pos(other, pos);
00952 }
00953
00954 void NodePath::
00955 set_y(const NodePath &other, float y) {
00956 nassertv_always(!is_empty());
00957 LPoint3f pos = get_pos(other);
00958 pos[1] = y;
00959 set_pos(other, pos);
00960 }
00961
00962 void NodePath::
00963 set_z(const NodePath &other, float z) {
00964 nassertv_always(!is_empty());
00965 LPoint3f pos = get_pos(other);
00966 pos[2] = z;
00967 set_pos(other, pos);
00968 }
00969
00970
00971
00972
00973
00974
00975
00976 LPoint3f NodePath::
00977 get_pos(const NodePath &other) const {
00978 nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
00979 return get_transform(other)->get_pos();
00980 }
00981
00982
00983
00984
00985
00986
00987
00988 void NodePath::
00989 set_hpr(const NodePath &other, const LVecBase3f &hpr) {
00990 nassertv_always(!is_empty());
00991 CPT(TransformState) rel_transform = get_transform(other);
00992 nassertv(rel_transform->has_hpr());
00993
00994 CPT(TransformState) orig_transform = get_transform();
00995 if (orig_transform->has_components()) {
00996
00997
00998
00999
01000 const LVecBase3f &orig_pos = orig_transform->get_pos();
01001 const LVecBase3f &orig_scale = orig_transform->get_scale();
01002
01003 set_transform(other, rel_transform->set_hpr(hpr));
01004 const TransformState *new_transform = get_transform();
01005 if (new_transform->has_components()) {
01006 set_pos_hpr_scale(orig_pos, new_transform->get_hpr(), orig_scale);
01007 }
01008
01009 } else {
01010
01011
01012 set_transform(other, rel_transform->set_hpr(hpr));
01013 }
01014 }
01015
01016 void NodePath::
01017 set_h(const NodePath &other, float h) {
01018 nassertv_always(!is_empty());
01019 LVecBase3f hpr = get_hpr(other);
01020 hpr[0] = h;
01021 set_hpr(other, hpr);
01022 }
01023
01024 void NodePath::
01025 set_p(const NodePath &other, float p) {
01026 nassertv_always(!is_empty());
01027 LVecBase3f hpr = get_hpr(other);
01028 hpr[1] = p;
01029 set_hpr(other, hpr);
01030 }
01031
01032 void NodePath::
01033 set_r(const NodePath &other, float r) {
01034 nassertv_always(!is_empty());
01035 LVecBase3f hpr = get_hpr(other);
01036 hpr[2] = r;
01037 set_hpr(other, hpr);
01038 }
01039
01040
01041
01042
01043
01044
01045
01046 LVecBase3f NodePath::
01047 get_hpr(const NodePath &other) const {
01048 nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f));
01049 CPT(TransformState) transform = get_transform(other);
01050 nassertr(transform->has_hpr(), LVecBase3f(0.0f, 0.0f, 0.0f));
01051 return transform->get_hpr();
01052 }
01053
01054
01055
01056
01057
01058
01059
01060 LVecBase3f NodePath::
01061 get_hpr(const NodePath &other, float roll) const {
01062
01063
01064 LMatrix4f mat = get_mat(other);
01065 LVector3f scale, hpr, pos;
01066 decompose_matrix(mat, scale, hpr, pos, roll);
01067 return hpr;
01068 }
01069
01070
01071
01072
01073
01074
01075
01076 void NodePath::
01077 set_quat(const NodePath &other, const LQuaternionf &quat) {
01078 nassertv_always(!is_empty());
01079 CPT(TransformState) rel_transform = get_transform(other);
01080
01081 CPT(TransformState) orig_transform = get_transform();
01082 if (orig_transform->has_components()) {
01083
01084
01085
01086
01087 const LVecBase3f &orig_pos = orig_transform->get_pos();
01088 const LVecBase3f &orig_scale = orig_transform->get_scale();
01089
01090 set_transform(other, rel_transform->set_quat(quat));
01091 const TransformState *new_transform = get_transform();
01092 if (new_transform->has_components()) {
01093 set_pos_quat_scale(orig_pos, new_transform->get_quat(), orig_scale);
01094 }
01095
01096 } else {
01097
01098
01099 set_transform(other, rel_transform->set_quat(quat));
01100 }
01101 }
01102
01103
01104
01105
01106
01107
01108
01109 LQuaternionf NodePath::
01110 get_quat(const NodePath &other) const {
01111 nassertr_always(!is_empty(), LQuaternionf::ident_quat());
01112 CPT(TransformState) transform = get_transform(other);
01113 return transform->get_quat();
01114 }
01115
01116
01117
01118
01119
01120
01121
01122 void NodePath::
01123 set_scale(const NodePath &other, const LVecBase3f &scale) {
01124 nassertv_always(!is_empty());
01125 CPT(TransformState) rel_transform = get_transform(other);
01126
01127 CPT(TransformState) orig_transform = get_transform();
01128 if (orig_transform->has_components()) {
01129
01130
01131
01132
01133 const LVecBase3f &orig_pos = orig_transform->get_pos();
01134 const LVecBase3f &orig_hpr = orig_transform->get_hpr();
01135
01136 set_transform(other, rel_transform->set_scale(scale));
01137 const TransformState *new_transform = get_transform();
01138 if (new_transform->has_components()) {
01139 set_pos_hpr_scale(orig_pos, orig_hpr, new_transform->get_scale());
01140 }
01141
01142 } else {
01143
01144
01145 set_transform(other, rel_transform->set_scale(scale));
01146 }
01147 }
01148
01149 void NodePath::
01150 set_sx(const NodePath &other, float sx) {
01151 nassertv_always(!is_empty());
01152 LVecBase3f scale = get_scale(other);
01153 scale[0] = sx;
01154 set_scale(other, scale);
01155 }
01156
01157 void NodePath::
01158 set_sy(const NodePath &other, float sy) {
01159 nassertv_always(!is_empty());
01160 LVecBase3f scale = get_scale(other);
01161 scale[1] = sy;
01162 set_scale(other, scale);
01163 }
01164
01165 void NodePath::
01166 set_sz(const NodePath &other, float sz) {
01167 nassertv_always(!is_empty());
01168 LVecBase3f scale = get_scale(other);
01169 scale[2] = sz;
01170 set_scale(other, scale);
01171 }
01172
01173
01174
01175
01176
01177
01178
01179 LVecBase3f NodePath::
01180 get_scale(const NodePath &other) const {
01181 nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f));
01182 CPT(TransformState) transform = get_transform(other);
01183 return transform->get_scale();
01184 }
01185
01186
01187
01188
01189
01190
01191
01192 void NodePath::
01193 set_pos_hpr(const NodePath &other, const LVecBase3f &pos,
01194 const LVecBase3f &hpr) {
01195 nassertv_always(!is_empty());
01196 CPT(TransformState) rel_transform = get_transform(other);
01197
01198 CPT(TransformState) orig_transform = get_transform();
01199 if (orig_transform->has_components()) {
01200
01201
01202
01203
01204 const LVecBase3f &orig_scale = orig_transform->get_scale();
01205
01206 set_transform(other, TransformState::make_pos_hpr_scale
01207 (pos, hpr, rel_transform->get_scale()));
01208 const TransformState *new_transform = get_transform();
01209 if (new_transform->has_components()) {
01210 set_pos_hpr_scale(new_transform->get_pos(), new_transform->get_hpr(),
01211 orig_scale);
01212 }
01213
01214 } else {
01215
01216
01217 set_transform(other, TransformState::make_pos_hpr_scale
01218 (pos, hpr, rel_transform->get_scale()));
01219 }
01220 }
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230 void NodePath::
01231 set_hpr_scale(const NodePath &other, const LVecBase3f &hpr, const LVecBase3f &scale) {
01232
01233
01234
01235
01236 nassertv_always(!is_empty());
01237 CPT(TransformState) transform = get_transform(other);
01238 transform = TransformState::make_pos_hpr_scale
01239 (transform->get_pos(), hpr, scale);
01240 set_transform(other, transform);
01241 }
01242
01243
01244
01245
01246
01247
01248
01249
01250 void NodePath::
01251 set_pos_hpr_scale(const NodePath &other,
01252 const LVecBase3f &pos, const LVecBase3f &hpr,
01253 const LVecBase3f &scale) {
01254 nassertv_always(!is_empty());
01255 set_transform(other, TransformState::make_pos_hpr_scale
01256 (pos, hpr, scale));
01257 }
01258
01259
01260
01261
01262
01263
01264
01265
01266 void NodePath::
01267 set_pos_quat_scale(const NodePath &other,
01268 const LVecBase3f &pos, const LQuaternionf &quat,
01269 const LVecBase3f &scale) {
01270 nassertv_always(!is_empty());
01271 set_transform(other, TransformState::make_pos_quat_scale
01272 (pos, quat, scale));
01273 }
01274
01275
01276
01277
01278
01279
01280
01281
01282 const LMatrix4f &NodePath::
01283 get_mat(const NodePath &other) const {
01284 CPT(TransformState) transform = get_transform(other);
01285
01286
01287
01288
01289 nassertr(transform->get_ref_count() > 1, LMatrix4f::ident_mat());
01290 return transform->get_mat();
01291 }
01292
01293
01294
01295
01296
01297
01298
01299
01300 void NodePath::
01301 set_mat(const NodePath &other, const LMatrix4f &mat) {
01302 nassertv_always(!is_empty());
01303 set_transform(other, TransformState::make_mat(mat));
01304 }
01305
01306
01307
01308
01309
01310
01311
01312
01313 LPoint3f NodePath::
01314 get_relative_point(const NodePath &other, const LVecBase3f &point) {
01315 LPoint3f rel_point = LPoint3f(point) * other.get_mat(*this);
01316 return rel_point;
01317 }
01318
01319
01320
01321
01322
01323
01324
01325
01326 void NodePath::
01327 look_at(const NodePath &other, const LPoint3f &point, const LVector3f &up) {
01328 nassertv_always(!is_empty());
01329
01330 NodePath parent = get_parent();
01331 LPoint3f rel_point = point * other.get_mat(parent);
01332
01333 LPoint3f pos = get_pos();
01334
01335 LQuaternionf quat;
01336 ::look_at(quat, rel_point - pos, up);
01337 set_quat(quat);
01338 }
01339
01340
01341
01342
01343
01344
01345
01346
01347 void NodePath::
01348 heads_up(const NodePath &other, const LPoint3f &point, const LVector3f &up) {
01349 nassertv_always(!is_empty());
01350
01351 NodePath parent = get_parent();
01352 LPoint3f rel_point = point * other.get_mat(parent);
01353
01354 LPoint3f pos = get_pos();
01355
01356 LQuaternionf quat;
01357 ::heads_up(quat, rel_point - pos, up);
01358 set_quat(quat);
01359 }
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369 void NodePath::
01370 set_color(float r, float g, float b, float a,
01371 int priority) {
01372 set_color(Colorf(r, g, b, a), priority);
01373 }
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383 void NodePath::
01384 set_color(const Colorf &color, int priority) {
01385 nassertv_always(!is_empty());
01386 node()->set_attrib(ColorAttrib::make_flat(color), priority);
01387 }
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399 void NodePath::
01400 set_color_off(int priority) {
01401 nassertv_always(!is_empty());
01402 node()->set_attrib(ColorAttrib::make_vertex(), priority);
01403 }
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413 void NodePath::
01414 clear_color() {
01415 nassertv_always(!is_empty());
01416 node()->clear_attrib(ColorAttrib::get_class_type());
01417 }
01418
01419
01420
01421
01422
01423
01424
01425 bool NodePath::
01426 has_color() const {
01427 nassertr_always(!is_empty(), false);
01428 return node()->has_attrib(ColorAttrib::get_class_type());
01429 }
01430
01431
01432
01433
01434
01435
01436
01437 Colorf NodePath::
01438 get_color() const {
01439 nassertr_always(!is_empty(), false);
01440 const RenderAttrib *attrib =
01441 node()->get_attrib(ColorAttrib::get_class_type());
01442 if (attrib != (const RenderAttrib *)NULL) {
01443 const ColorAttrib *ca = DCAST(ColorAttrib, attrib);
01444 if (ca->get_color_type() == ColorAttrib::T_flat) {
01445 return ca->get_color();
01446 }
01447 }
01448
01449 pgraph_cat.warning()
01450 << "get_color() called on " << *this << " which has no color set.\n";
01451
01452 return Colorf(1.0f, 1.0f, 1.0f, 1.0f);
01453 }
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479 void NodePath::
01480 set_bin(const string &bin_name, int draw_order, int priority) {
01481 nassertv_always(!is_empty());
01482 node()->set_attrib(CullBinAttrib::make(bin_name, draw_order), priority);
01483 }
01484
01485
01486
01487
01488
01489
01490
01491 void NodePath::
01492 clear_bin() {
01493 nassertv_always(!is_empty());
01494 node()->clear_attrib(CullBinAttrib::get_class_type());
01495 }
01496
01497
01498
01499
01500
01501
01502
01503
01504 bool NodePath::
01505 has_bin() const {
01506 nassertr_always(!is_empty(), false);
01507 return node()->has_attrib(CullBinAttrib::get_class_type());
01508 }
01509
01510
01511
01512
01513
01514
01515
01516
01517 string NodePath::
01518 get_bin_name() const {
01519 nassertr_always(!is_empty(), string());
01520 const RenderAttrib *attrib =
01521 node()->get_attrib(CullBinAttrib::get_class_type());
01522 if (attrib != (const RenderAttrib *)NULL) {
01523 const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib);
01524 return ba->get_bin_name();
01525 }
01526
01527 return string();
01528 }
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538 int NodePath::
01539 get_bin_draw_order() const {
01540 nassertr_always(!is_empty(), false);
01541 const RenderAttrib *attrib =
01542 node()->get_attrib(CullBinAttrib::get_class_type());
01543 if (attrib != (const RenderAttrib *)NULL) {
01544 const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib);
01545 return ba->get_draw_order();
01546 }
01547
01548 return 0;
01549 }
01550
01551
01552
01553
01554
01555
01556
01557 void NodePath::
01558 set_texture(Texture *tex, int priority) {
01559 nassertv_always(!is_empty());
01560 node()->set_attrib(TextureAttrib::make(tex), priority);
01561 }
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573 void NodePath::
01574 set_texture_off(int priority) {
01575 nassertv_always(!is_empty());
01576 node()->set_attrib(TextureAttrib::make_off(), priority);
01577 }
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588 void NodePath::
01589 clear_texture() {
01590 nassertv_always(!is_empty());
01591 node()->clear_attrib(TextureAttrib::get_class_type());
01592 }
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604 bool NodePath::
01605 has_texture() const {
01606 nassertr_always(!is_empty(), false);
01607 const RenderAttrib *attrib =
01608 node()->get_attrib(TextureAttrib::get_class_type());
01609 if (attrib != (const RenderAttrib *)NULL) {
01610 const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
01611 return !ta->is_off();
01612 }
01613
01614 return false;
01615 }
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627 bool NodePath::
01628 has_texture_off() const {
01629 nassertr_always(!is_empty(), false);
01630 const RenderAttrib *attrib =
01631 node()->get_attrib(ColorAttrib::get_class_type());
01632 if (attrib != (const RenderAttrib *)NULL) {
01633 const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
01634 return ta->is_off();
01635 }
01636
01637 return false;
01638 }
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652 Texture *NodePath::
01653 get_texture() const {
01654 nassertr_always(!is_empty(), NULL);
01655 const RenderAttrib *attrib =
01656 node()->get_attrib(TextureAttrib::get_class_type());
01657 if (attrib != (const RenderAttrib *)NULL) {
01658 const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
01659 return ta->get_texture();
01660 }
01661
01662 return NULL;
01663 }
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673 Texture *NodePath::
01674 find_texture(const string &name) const {
01675 GlobPattern glob(name);
01676 return r_find_texture(node(), get_net_state(), glob);
01677 }
01678
01679
01680
01681
01682
01683
01684
01685 TextureCollection NodePath::
01686 find_all_textures() const {
01687 Textures textures;
01688 r_find_all_textures(node(), get_net_state(), textures);
01689
01690 TextureCollection tc;
01691 Textures::iterator ti;
01692 for (ti = textures.begin(); ti != textures.end(); ++ti) {
01693 tc.add_texture(*ti);
01694 }
01695 return tc;
01696 }
01697
01698
01699
01700
01701
01702
01703
01704
01705 TextureCollection NodePath::
01706 find_all_textures(const string &name) const {
01707 Textures textures;
01708 r_find_all_textures(node(), get_net_state(), textures);
01709
01710 GlobPattern glob(name);
01711
01712 TextureCollection tc;
01713 Textures::iterator ti;
01714 for (ti = textures.begin(); ti != textures.end(); ++ti) {
01715 Texture *texture = (*ti);
01716 if (glob.matches(texture->get_name())) {
01717 tc.add_texture(texture);
01718 }
01719 }
01720 return tc;
01721 }
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733 void NodePath::
01734 set_material(Material *mat, int priority) {
01735 nassertv_always(!is_empty());
01736 nassertv(mat != NULL);
01737
01738
01739
01740
01741
01742
01743 PT(Material) temp = new Material(*mat);
01744 const Material *mp = MaterialPool::get_material(temp);
01745
01746 node()->set_attrib(MaterialAttrib::make(mp), priority);
01747 }
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759 void NodePath::
01760 set_material_off(int priority) {
01761 nassertv_always(!is_empty());
01762 node()->set_attrib(MaterialAttrib::make_off(), priority);
01763 }
01764
01765
01766
01767
01768
01769
01770
01771
01772 void NodePath::
01773 clear_material() {
01774 nassertv_always(!is_empty());
01775 node()->clear_attrib(MaterialAttrib::get_class_type());
01776 }
01777
01778
01779
01780
01781
01782
01783
01784 bool NodePath::
01785 has_material() const {
01786 nassertr_always(!is_empty(), false);
01787 const RenderAttrib *attrib =
01788 node()->get_attrib(MaterialAttrib::get_class_type());
01789 if (attrib != (const RenderAttrib *)NULL) {
01790 const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
01791 return !ma->is_off();
01792 }
01793
01794 return false;
01795 }
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811 PT(Material) NodePath::
01812 get_material() const {
01813 nassertr_always(!is_empty(), NULL);
01814 const RenderAttrib *attrib =
01815 node()->get_attrib(MaterialAttrib::get_class_type());
01816 if (attrib != (const RenderAttrib *)NULL) {
01817 const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
01818 return new Material(*ma->get_material());
01819 }
01820
01821 return NULL;
01822 }
01823
01824
01825
01826
01827
01828
01829
01830 void NodePath::
01831 set_fog(Fog *fog, int priority) {
01832 nassertv_always(!is_empty());
01833 node()->set_attrib(FogAttrib::make(fog), priority);
01834 }
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846 void NodePath::
01847 set_fog_off(int priority) {
01848 nassertv_always(!is_empty());
01849 node()->set_attrib(FogAttrib::make_off(), priority);
01850 }
01851
01852
01853
01854
01855
01856
01857
01858
01859
01860
01861 void NodePath::
01862 clear_fog() {
01863 nassertv_always(!is_empty());
01864 node()->clear_attrib(FogAttrib::get_class_type());
01865 }
01866
01867
01868
01869
01870
01871
01872
01873
01874
01875
01876
01877 bool NodePath::
01878 has_fog() const {
01879 nassertr_always(!is_empty(), false);
01880 const RenderAttrib *attrib =
01881 node()->get_attrib(FogAttrib::get_class_type());
01882 if (attrib != (const RenderAttrib *)NULL) {
01883 const FogAttrib *fa = DCAST(FogAttrib, attrib);
01884 return !fa->is_off();
01885 }
01886
01887 return false;
01888 }
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900 bool NodePath::
01901 has_fog_off() const {
01902 nassertr_always(!is_empty(), false);
01903 const RenderAttrib *attrib =
01904 node()->get_attrib(FogAttrib::get_class_type());
01905 if (attrib != (const RenderAttrib *)NULL) {
01906 const FogAttrib *fa = DCAST(FogAttrib, attrib);
01907 return fa->is_off();
01908 }
01909
01910 return false;
01911 }
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923 Fog *NodePath::
01924 get_fog() const {
01925 nassertr_always(!is_empty(), NULL);
01926 const RenderAttrib *attrib =
01927 node()->get_attrib(FogAttrib::get_class_type());
01928 if (attrib != (const RenderAttrib *)NULL) {
01929 const FogAttrib *fa = DCAST(FogAttrib, attrib);
01930 return fa->get_fog();
01931 }
01932
01933 return NULL;
01934 }
01935
01936
01937
01938
01939
01940
01941
01942 void NodePath::
01943 set_render_mode_wireframe(int priority) {
01944 nassertv_always(!is_empty());
01945 node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_wireframe), priority);
01946 }
01947
01948
01949
01950
01951
01952
01953
01954
01955 void NodePath::
01956 set_render_mode_filled(int priority) {
01957 nassertv_always(!is_empty());
01958 node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled), priority);
01959 }
01960
01961
01962
01963
01964
01965
01966
01967
01968
01969 void NodePath::
01970 clear_render_mode() {
01971 nassertv_always(!is_empty());
01972 node()->clear_attrib(RenderModeAttrib::get_class_type());
01973 }
01974
01975
01976
01977
01978
01979
01980
01981
01982
01983 bool NodePath::
01984 has_render_mode() const {
01985 nassertr_always(!is_empty(), false);
01986 return node()->has_attrib(RenderModeAttrib::get_class_type());
01987 }
01988
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998 void NodePath::
01999 set_two_sided(bool two_sided, int priority) {
02000 nassertv_always(!is_empty());
02001
02002 CullFaceAttrib::Mode mode =
02003 two_sided ?
02004 CullFaceAttrib::M_cull_none :
02005 CullFaceAttrib::M_cull_clockwise;
02006
02007 node()->set_attrib(CullFaceAttrib::make(mode), priority);
02008 }
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021 void NodePath::
02022 clear_two_sided() {
02023 nassertv_always(!is_empty());
02024 node()->clear_attrib(CullFaceAttrib::get_class_type());
02025 }
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035
02036 bool NodePath::
02037 has_two_sided() const {
02038 nassertr_always(!is_empty(), false);
02039 return node()->has_attrib(CullFaceAttrib::get_class_type());
02040 }
02041
02042
02043
02044
02045
02046
02047
02048
02049
02050
02051
02052
02053 bool NodePath::
02054 get_two_sided() const {
02055 nassertr_always(!is_empty(), false);
02056 const RenderAttrib *attrib =
02057 node()->get_attrib(CullFaceAttrib::get_class_type());
02058 if (attrib != (const RenderAttrib *)NULL) {
02059 const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, attrib);
02060 return (cfa->get_actual_mode() == CullFaceAttrib::M_cull_none);
02061 }
02062
02063 return false;
02064 }
02065
02066 #if 0
02067
02068
02069
02070
02071
02072
02073
02074
02075
02076
02077 void NodePath::
02078 set_alpha_test(RenderAttrib::PandaCompareFunc alpha_test_mode,float reference_alpha, int priority) {
02079 nassertv_always(!is_empty());
02080 node()->set_attrib(AlphaTestAttrib::make(alpha_test_mode,reference_alpha), priority);
02081 }
02082
02083
02084
02085
02086
02087
02088
02089 void NodePath::
02090 clear_alpha_test() {
02091 nassertv_always(!is_empty());
02092 node()->clear_attrib(AlphaTestAttrib::get_class_type());
02093 }
02094
02095
02096
02097
02098
02099
02100
02101
02102
02103
02104 bool NodePath::
02105 has_alpha_test() const {
02106 nassertr_always(!is_empty(), false);
02107 return node()->has_attrib(AlphaTestAttrib::get_class_type());
02108 }
02109
02110
02111
02112
02113
02114
02115
02116
02117
02118
02119 bool NodePath::
02120 get_alpha_test() const {
02121 nassertr_always(!is_empty(), false);
02122 const RenderAttrib *attrib =
02123 node()->get_attrib(AlphaTestAttrib::get_class_type());
02124 if (attrib != (const RenderAttrib *)NULL) {
02125 const AlphaTestAttrib *dta = DCAST(AlphaTestAttrib, attrib);
02126 return (dta->get_mode() != AlphaTestAttrib::M_none);
02127 }
02128
02129 return false;
02130 }
02131 #endif
02132
02133
02134
02135
02136
02137
02138
02139
02140
02141 void NodePath::
02142 set_depth_test(bool depth_test, int priority) {
02143 nassertv_always(!is_empty());
02144
02145 DepthTestAttrib::PandaCompareFunc mode =
02146 depth_test ?
02147 DepthTestAttrib::M_less :
02148 DepthTestAttrib::M_none;
02149
02150 node()->set_attrib(DepthTestAttrib::make(mode), priority);
02151 }
02152
02153
02154
02155
02156
02157
02158
02159 void NodePath::
02160 clear_depth_test() {
02161 nassertv_always(!is_empty());
02162 node()->clear_attrib(DepthTestAttrib::get_class_type());
02163 }
02164
02165
02166
02167
02168
02169
02170
02171
02172
02173
02174 bool NodePath::
02175 has_depth_test() const {
02176 nassertr_always(!is_empty(), false);
02177 return node()->has_attrib(DepthTestAttrib::get_class_type());
02178 }
02179
02180
02181
02182
02183
02184
02185
02186
02187
02188
02189 bool NodePath::
02190 get_depth_test() const {
02191 nassertr_always(!is_empty(), false);
02192 const RenderAttrib *attrib =
02193 node()->get_attrib(DepthTestAttrib::get_class_type());
02194 if (attrib != (const RenderAttrib *)NULL) {
02195 const DepthTestAttrib *dta = DCAST(DepthTestAttrib, attrib);
02196 return (dta->get_mode() != DepthTestAttrib::M_none);
02197 }
02198
02199 return false;
02200 }
02201
02202
02203
02204
02205
02206
02207
02208
02209
02210
02211 void NodePath::
02212 set_depth_write(bool depth_write, int priority) {
02213 nassertv_always(!is_empty());
02214
02215 DepthWriteAttrib::Mode mode =
02216 depth_write ?
02217 DepthWriteAttrib::M_on :
02218 DepthWriteAttrib::M_off;
02219
02220 node()->set_attrib(DepthWriteAttrib::make(mode), priority);
02221 }
02222
02223
02224
02225
02226
02227
02228
02229 void NodePath::
02230 clear_depth_write() {
02231 nassertv_always(!is_empty());
02232 node()->clear_attrib(DepthWriteAttrib::get_class_type());
02233 }
02234
02235
02236
02237
02238
02239
02240
02241
02242
02243
02244 bool NodePath::
02245 has_depth_write() const {
02246 nassertr_always(!is_empty(), false);
02247 return node()->has_attrib(DepthWriteAttrib::get_class_type());
02248 }
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258
02259 bool NodePath::
02260 get_depth_write() const {
02261 nassertr_always(!is_empty(), false);
02262 const RenderAttrib *attrib =
02263 node()->get_attrib(DepthWriteAttrib::get_class_type());
02264 if (attrib != (const RenderAttrib *)NULL) {
02265 const DepthWriteAttrib *dta = DCAST(DepthWriteAttrib, attrib);
02266 return (dta->get_mode() != DepthWriteAttrib::M_off);
02267 }
02268
02269 return false;
02270 }
02271
02272
02273
02274
02275
02276
02277
02278
02279 void NodePath::
02280 do_billboard_axis(const NodePath &camera, float offset) {
02281 nassertv_always(!is_empty());
02282
02283 NodePath parent = get_parent();
02284 LMatrix4f rel_mat = camera.get_mat(parent);
02285
02286 LVector3f up = LVector3f::up();
02287 LVector3f rel_pos = -rel_mat.get_row3(3);
02288
02289 LQuaternionf quat;
02290 ::heads_up(quat, rel_pos, up);
02291 set_quat(quat);
02292
02293
02294
02295 if (offset != 0.0f) {
02296 LVector3f translate = rel_mat.get_row3(3);
02297 translate.normalize();
02298 translate *= offset;
02299 set_pos(translate);
02300 }
02301 }
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312 void NodePath::
02313 do_billboard_point_eye(const NodePath &camera, float offset) {
02314 nassertv_always(!is_empty());
02315
02316 NodePath parent = get_parent();
02317 LMatrix4f rel_mat = camera.get_mat(parent);
02318
02319 LVector3f up = LVector3f::up() * rel_mat;
02320 LVector3f rel_pos = LVector3f::forward() * rel_mat;
02321
02322 LQuaternionf quat;
02323 ::look_at(quat, rel_pos, up);
02324 set_quat(quat);
02325
02326
02327
02328 if (offset != 0.0f) {
02329 LVector3f translate = rel_mat.get_row3(3);
02330 translate.normalize();
02331 translate *= offset;
02332 set_pos(translate);
02333 }
02334 }
02335
02336
02337
02338
02339
02340
02341
02342
02343 void NodePath::
02344 do_billboard_point_world(const NodePath &camera, float offset) {
02345 nassertv_always(!is_empty());
02346
02347 NodePath parent = get_parent();
02348 LMatrix4f rel_mat = camera.get_mat(parent);
02349
02350 LVector3f up = LVector3f::up();
02351 LVector3f rel_pos = -rel_mat.get_row3(3);
02352
02353 LQuaternionf quat;
02354 ::look_at(quat, rel_pos, up);
02355 set_quat(quat);
02356
02357
02358
02359 if (offset != 0.0f) {
02360 LVector3f translate = rel_mat.get_row3(3);
02361 translate.normalize();
02362 translate *= offset;
02363 set_pos(translate);
02364 }
02365 }
02366
02367
02368
02369
02370
02371
02372
02373
02374
02375 void NodePath::
02376 set_billboard_axis(const NodePath &camera, float offset) {
02377 nassertv_always(!is_empty());
02378 CPT(RenderEffect) billboard = BillboardEffect::make
02379 (LVector3f::up(), false, true,
02380 offset, camera, LPoint3f(0.0f, 0.0f, 0.0f));
02381 node()->set_effect(billboard);
02382 }
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392
02393 void NodePath::
02394 set_billboard_point_eye(const NodePath &camera, float offset) {
02395 nassertv_always(!is_empty());
02396 CPT(RenderEffect) billboard = BillboardEffect::make
02397 (LVector3f::up(), true, false,
02398 offset, camera, LPoint3f(0.0f, 0.0f, 0.0f));
02399 node()->set_effect(billboard);
02400 }
02401
02402
02403
02404
02405
02406
02407
02408
02409
02410 void NodePath::
02411 set_billboard_point_world(const NodePath &camera, float offset) {
02412 nassertv_always(!is_empty());
02413 CPT(RenderEffect) billboard = BillboardEffect::make
02414 (LVector3f::up(), false, false,
02415 offset, camera, LPoint3f(0.0f, 0.0f, 0.0f));
02416 node()->set_effect(billboard);
02417 }
02418
02419
02420
02421
02422
02423
02424 void NodePath::
02425 clear_billboard() {
02426 nassertv_always(!is_empty());
02427 node()->clear_effect(BillboardEffect::get_class_type());
02428 }
02429
02430
02431
02432
02433
02434
02435
02436 bool NodePath::
02437 has_billboard() const {
02438 nassertr_always(!is_empty(), false);
02439 return node()->has_effect(BillboardEffect::get_class_type());
02440 }
02441
02442
02443
02444
02445
02446
02447
02448
02449
02450 void NodePath::
02451 set_compass(const NodePath &reference) {
02452 nassertv_always(!is_empty());
02453 node()->set_effect(CompassEffect::make(reference));
02454 }
02455
02456
02457
02458
02459
02460
02461 void NodePath::
02462 clear_compass() {
02463 nassertv_always(!is_empty());
02464 node()->clear_effect(CompassEffect::get_class_type());
02465 }
02466
02467
02468
02469
02470
02471
02472
02473 bool NodePath::
02474 has_compass() const {
02475 nassertr_always(!is_empty(), false);
02476 return node()->has_effect(CompassEffect::get_class_type());
02477 }
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487 void NodePath::
02488 set_transparency(bool transparency, int priority) {
02489 nassertv_always(!is_empty());
02490
02491 TransparencyAttrib::Mode mode =
02492 transparency ?
02493 TransparencyAttrib::M_alpha :
02494 TransparencyAttrib::M_none;
02495
02496 node()->set_attrib(TransparencyAttrib::make(mode), priority);
02497 }
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508
02509 void NodePath::
02510 clear_transparency() {
02511 nassertv_always(!is_empty());
02512 node()->clear_attrib(TransparencyAttrib::get_class_type());
02513 }
02514
02515
02516
02517
02518
02519
02520
02521
02522
02523
02524
02525 bool NodePath::
02526 has_transparency() const {
02527 nassertr_always(!is_empty(), false);
02528 return node()->has_attrib(TransparencyAttrib::get_class_type());
02529 }
02530
02531
02532
02533
02534
02535
02536
02537
02538
02539
02540
02541
02542 bool NodePath::
02543 get_transparency() const {
02544 nassertr_always(!is_empty(), false);
02545 const RenderAttrib *attrib =
02546 node()->get_attrib(TransparencyAttrib::get_class_type());
02547 if (attrib != (const RenderAttrib *)NULL) {
02548 const TransparencyAttrib *ta = DCAST(TransparencyAttrib, attrib);
02549 return (ta->get_mode() != TransparencyAttrib::M_none);
02550 }
02551
02552 return false;
02553 }
02554
02555
02556
02557
02558
02559
02560
02561
02562
02563
02564 NodePath NodePath::
02565 get_hidden_ancestor(DrawMask camera_mask) const {
02566 NodePathComponent *comp;
02567 for (comp = _head;
02568 comp != (NodePathComponent *)NULL;
02569 comp = comp->get_next()) {
02570 PandaNode *node = comp->get_node();
02571 if ((node->get_draw_mask() & camera_mask).is_zero()) {
02572 NodePath result;
02573 result._head = comp;
02574 return result;
02575 }
02576 }
02577
02578 return not_found();
02579 }
02580
02581
02582
02583
02584
02585
02586
02587
02588
02589 NodePath NodePath::
02590 get_stashed_ancestor() const {
02591 NodePathComponent *comp = _head;
02592 if (comp != (NodePathComponent *)NULL) {
02593 NodePathComponent *next = comp->get_next();
02594
02595 while (next != (NodePathComponent *)NULL) {
02596 PandaNode *node = comp->get_node();
02597 PandaNode *parent_node = next->get_node();
02598
02599 if (parent_node->find_stashed(node) >= 0) {
02600 NodePath result;
02601 result._head = comp;
02602 return result;
02603 }
02604
02605 comp = next;
02606 next = next->get_next();
02607 }
02608 }
02609
02610 return not_found();
02611 }
02612
02613
02614
02615
02616
02617
02618
02619
02620 bool NodePath::
02621 verify_complete() const {
02622 if (is_empty()) {
02623 return true;
02624 }
02625
02626 uncollapse_head();
02627 const NodePathComponent *comp = _head;
02628 nassertr(comp != (const NodePathComponent *)NULL, false);
02629
02630 PandaNode *node = comp->get_node();
02631 nassertr(node != (const PandaNode *)NULL, false);
02632 int length = comp->get_length();
02633
02634 comp = comp->get_next();
02635 length--;
02636 while (comp != (const NodePathComponent *)NULL) {
02637 PandaNode *next_node = comp->get_node();
02638 nassertr(next_node != (const PandaNode *)NULL, false);
02639
02640 if (node->find_parent(next_node) < 0) {
02641 pgraph_cat.warning()
02642 << *this << " is incomplete; " << *node << " is not a child of "
02643 << *next_node << "\n";
02644 return false;
02645 }
02646
02647 if (comp->get_length() != length) {
02648 pgraph_cat.warning()
02649 << *this << " is incomplete; length at " << *next_node
02650 << " indicates " << comp->get_length() << " while length at "
02651 << *node << " indicates " << length << "\n";
02652 return false;
02653 }
02654
02655 node = next_node;
02656 comp = comp->get_next();
02657 length--;
02658 }
02659
02660
02661 if (length == 0 && node->get_num_parents() == 0) {
02662 return true;
02663 }
02664
02665 pgraph_cat.warning()
02666 << *this << " is incomplete; top node " << *node << " indicates length "
02667 << length << " with " << node->get_num_parents() << " parents.\n";
02668 return false;
02669 }
02670
02671
02672
02673
02674
02675
02676
02677
02678
02679
02680
02681
02682
02683
02684
02685
02686
02687
02688 void NodePath::
02689 prepare_scene(GraphicsStateGuardianBase *gsg, bool force_retained_mode) {
02690 nassertv_always(!is_empty());
02691
02692 CPT(RenderState) net_state = get_net_state();
02693 r_prepare_scene(node(), net_state, gsg,
02694 retained_mode || force_retained_mode);
02695 }
02696
02697
02698
02699
02700
02701
02702
02703
02704
02705
02706 void NodePath::
02707 show_bounds() {
02708 nassertv_always(!is_empty());
02709 node()->set_effect(ShowBoundsEffect::make());
02710 }
02711
02712
02713
02714
02715
02716
02717
02718 void NodePath::
02719 hide_bounds() {
02720 nassertv_always(!is_empty());
02721 node()->clear_effect(ShowBoundsEffect::get_class_type());
02722 }
02723
02724
02725
02726
02727
02728
02729
02730
02731
02732 PT(BoundingVolume) NodePath::
02733 get_bounds() const {
02734 nassertr_always(!is_empty(), new BoundingSphere);
02735 return node()->get_bound().make_copy();
02736 }
02737
02738
02739
02740
02741
02742
02743
02744
02745
02746
02747
02748
02749
02750
02751
02752
02753
02754 void NodePath::
02755 force_recompute_bounds() {
02756 nassertv_always(!is_empty());
02757 r_force_recompute_bounds(node());
02758 }
02759
02760
02761
02762
02763
02764
02765
02766
02767 void NodePath::
02768 write_bounds(ostream &out) const {
02769 get_bounds()->write(out);
02770 }
02771
02772
02773
02774
02775
02776
02777
02778
02779
02780
02781
02782
02783
02784 bool NodePath::
02785 calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point) {
02786 min_point.set(0.0f, 0.0f, 0.0f);
02787 max_point.set(0.0f, 0.0f, 0.0f);
02788 nassertr_always(!is_empty(), false);
02789
02790 bool found_any = false;
02791 node()->calc_tight_bounds(min_point, max_point, found_any,
02792 TransformState::make_identity());
02793
02794 return found_any;
02795 }
02796
02797
02798
02799
02800
02801
02802
02803
02804
02805
02806
02807
02808
02809
02810
02811
02812
02813
02814
02815
02816
02817
02818
02819
02820
02821 int NodePath::
02822 flatten_light() {
02823 nassertr_always(!is_empty(), 0);
02824 SceneGraphReducer gr;
02825 gr.apply_attribs(node());
02826
02827 return 0;
02828 }
02829
02830
02831
02832
02833
02834
02835
02836
02837
02838
02839
02840
02841
02842
02843
02844
02845
02846
02847
02848
02849
02850
02851
02852
02853
02854 int NodePath::
02855 flatten_medium() {
02856 nassertr_always(!is_empty(), 0);
02857 SceneGraphReducer gr;
02858 gr.apply_attribs(node());
02859 int num_removed = gr.flatten(node(), false);
02860
02861 return num_removed;
02862 }
02863
02864
02865
02866
02867
02868
02869
02870
02871
02872
02873
02874
02875
02876
02877
02878
02879
02880
02881 int NodePath::
02882 flatten_strong() {
02883 nassertr_always(!is_empty(), 0);
02884 SceneGraphReducer gr;
02885 gr.apply_attribs(node());
02886 int num_removed = gr.flatten(node(), true);
02887
02888 return num_removed;
02889 }
02890
02891
02892
02893
02894
02895
02896
02897
02898
02899
02900 bool NodePath::
02901 write_bam_file(const string &filename) const {
02902 nassertr_always(!is_empty(), false);
02903
02904 BamFile bam_file;
02905
02906 bool okflag = false;
02907
02908 if (bam_file.open_write(filename)) {
02909 if (bam_file.write_object(node())) {
02910 okflag = true;
02911 }
02912 bam_file.close();
02913 }
02914 return okflag;
02915 }
02916
02917
02918
02919
02920
02921
02922
02923
02924
02925
02926 void NodePath::
02927 uncollapse_head() const {
02928 if (_head != (NodePathComponent *)NULL && _head->is_collapsed()) {
02929 ((NodePath *)this)->_head = _head->uncollapse();
02930 }
02931 }
02932
02933
02934
02935
02936
02937
02938
02939
02940
02941 void NodePath::
02942 find_common_ancestor(const NodePath &a, const NodePath &b,
02943 int &a_count, int &b_count) {
02944 nassertv(!a.is_empty() && !b.is_empty());
02945 a.uncollapse_head();
02946 b.uncollapse_head();
02947
02948 NodePathComponent *ac = a._head;
02949 NodePathComponent *bc = b._head;
02950 a_count = 0;
02951 b_count = 0;
02952
02953
02954 while (ac->get_length() > bc->get_length()) {
02955 nassertv(ac != (NodePathComponent *)NULL);
02956 ac = ac->get_next();
02957 a_count++;
02958 }
02959 while (bc->get_length() > ac->get_length()) {
02960 nassertv(bc != (NodePathComponent *)NULL);
02961 bc = bc->get_next();
02962 b_count++;
02963 }
02964
02965
02966 while (ac != bc) {
02967
02968 nassertv(ac != (NodePathComponent *)NULL);
02969 nassertv(bc != (NodePathComponent *)NULL);
02970 ac = ac->get_next();
02971 a_count++;
02972 bc = bc->get_next();
02973 b_count++;
02974 }
02975 }
02976
02977
02978
02979
02980
02981
02982
02983 CPT(RenderState) NodePath::
02984 r_get_net_state(NodePathComponent *comp) const {
02985 if (comp == (NodePathComponent *)NULL) {
02986 return RenderState::make_empty();
02987 } else {
02988 CPT(RenderState) state = comp->get_node()->get_state();
02989 return r_get_net_state(comp->get_next())->compose(state);
02990 }
02991 }
02992
02993
02994
02995
02996
02997
02998
02999
03000
03001 CPT(RenderState) NodePath::
03002 r_get_partial_state(NodePathComponent *comp, int n) const {
03003 if (n == 0 || comp == (NodePathComponent *)NULL) {
03004 return RenderState::make_empty();
03005 } else {
03006 CPT(RenderState) state = comp->get_node()->get_state();
03007 return r_get_partial_state(comp->get_next(), n - 1)->compose(state);
03008 }
03009 }
03010
03011
03012
03013
03014
03015
03016
03017 CPT(TransformState) NodePath::
03018 r_get_net_transform(NodePathComponent *comp) const {
03019 if (comp == (NodePathComponent *)NULL) {
03020 return TransformState::make_identity();
03021 } else {
03022 CPT(TransformState) transform = comp->get_node()->get_transform();
03023 return r_get_net_transform(comp->get_next())->compose(transform);
03024 }
03025 }
03026
03027
03028
03029
03030
03031
03032
03033
03034
03035 CPT(TransformState) NodePath::
03036 r_get_partial_transform(NodePathComponent *comp, int n) const {
03037 if (n == 0 || comp == (NodePathComponent *)NULL) {
03038 return TransformState::make_identity();
03039 } else {
03040 CPT(TransformState) transform = comp->get_node()->get_transform();
03041 return r_get_partial_transform(comp->get_next(), n - 1)->compose(transform);
03042 }
03043 }
03044
03045
03046
03047
03048
03049
03050
03051
03052
03053
03054 void NodePath::
03055 find_matches(NodePathCollection &result, const string &path,
03056 int max_matches) const {
03057 if (is_empty()) {
03058 pgraph_cat.warning()
03059 << "Attempt to extend an empty NodePath by '" << path
03060 << "'.\n";
03061 return;
03062 }
03063 FindApproxPath approx_path;
03064 if (approx_path.add_string(path)) {
03065 find_matches(result, approx_path, max_matches);
03066 }
03067 }
03068
03069
03070
03071
03072
03073
03074
03075
03076
03077
03078 void NodePath::
03079 find_matches(NodePathCollection &result, FindApproxPath &approx_path,
03080 int max_matches) const {
03081 if (is_empty()) {
03082 pgraph_cat.warning()
03083 << "Attempt to extend an empty NodePath by: " << approx_path << ".\n";
03084 return;
03085 }
03086 FindApproxLevelEntry start(WorkingNodePath(*this), approx_path);
03087 nassertv(start._node_path.is_valid());
03088 FindApproxLevel level;
03089 level.add_entry(start);
03090 r_find_matches(result, level, max_matches, _max_search_depth);
03091 }
03092
03093
03094
03095
03096
03097
03098 void NodePath::
03099 r_find_matches(NodePathCollection &result,
03100 const FindApproxLevel &level,
03101 int max_matches, int num_levels_remaining) const {
03102
03103
03104 if (num_levels_remaining <= 0) {
03105 return;
03106 }
03107 num_levels_remaining--;
03108
03109 FindApproxLevel next_level;
03110 bool okflag = true;
03111
03112
03113
03114 FindApproxLevel::Vec::const_iterator li;
03115 for (li = level._v.begin(); li != level._v.end() && okflag; ++li) {
03116 const FindApproxLevelEntry &entry = (*li);
03117
03118 if (entry.is_solution(0)) {
03119
03120 result.add_path(entry._node_path.get_node_path());
03121 } else {
03122 entry.consider_node(result, next_level, max_matches, 0);
03123 }
03124
03125 if (max_matches > 0 && result.get_num_paths() >= max_matches) {
03126
03127
03128
03129
03130 okflag = false;
03131 }
03132 }
03133
03134
03135 if (okflag) {
03136 r_find_matches(result, next_level, max_matches, num_levels_remaining);
03137 }
03138 }
03139
03140
03141
03142
03143
03144
03145
03146
03147 void NodePath::
03148 r_adjust_all_priorities(PandaNode *node, int adjustment) {
03149 node->set_state(node->get_state()->adjust_all_priorities(adjustment));
03150 if (node->is_geom_node()) {
03151 GeomNode *gnode;
03152 DCAST_INTO_V(gnode, node);
03153
03154 int num_geoms = gnode->get_num_geoms();
03155 for (int i = 0; i < num_geoms; i++) {
03156 gnode->set_geom_state(i, gnode->get_geom_state(i)->adjust_all_priorities(adjustment));
03157 }
03158 }
03159
03160 PandaNode::Children cr = node->get_children();
03161 int num_children = cr.get_num_children();
03162 for (int i = 0; i < num_children; i++) {
03163 r_adjust_all_priorities(cr.get_child(i), adjustment);
03164 }
03165 }
03166
03167
03168
03169
03170
03171
03172 void NodePath::
03173 r_force_recompute_bounds(PandaNode *node) {
03174 if (node->is_geom_node()) {
03175 GeomNode *gnode;
03176 DCAST_INTO_V(gnode, node);
03177
03178 int num_geoms = gnode->get_num_geoms();
03179 for (int i = 0; i < num_geoms; i++) {
03180 gnode->get_geom(i)->mark_bound_stale();
03181 }
03182 }
03183
03184 node->mark_bound_stale();
03185
03186
03187 PandaNode::Children cr = node->get_children();
03188 int num_children = cr.get_num_children();
03189 for (int i = 0; i < num_children; i++) {
03190 r_force_recompute_bounds(cr.get_child(i));
03191 }
03192 }
03193
03194
03195
03196
03197
03198
03199 Texture * NodePath::
03200 r_find_texture(PandaNode *node, const RenderState *state,
03201 const GlobPattern &glob) const {
03202 if (node->is_geom_node()) {
03203 GeomNode *gnode;
03204 DCAST_INTO_R(gnode, node, NULL);
03205
03206 int num_geoms = gnode->get_num_geoms();
03207 for (int i = 0; i < num_geoms; i++) {
03208 CPT(RenderState) geom_state =
03209 state->compose(gnode->get_geom_state(i));
03210
03211
03212 const RenderAttrib *attrib =
03213 geom_state->get_attrib(TextureAttrib::get_class_type());
03214 if (attrib != (const RenderAttrib *)NULL) {
03215 const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
03216 Texture *texture = ta->get_texture();
03217 if (texture != (Texture *)NULL) {
03218 if (glob.matches(texture->get_name())) {
03219 return texture;
03220 }
03221 }
03222 }
03223 }
03224 }
03225
03226
03227 PandaNode::Children cr = node->get_children();
03228 int num_children = cr.get_num_children();
03229 for (int i = 0; i < num_children; i++) {
03230 PandaNode *child = cr.get_child(i);
03231 CPT(RenderState) next_state = state->compose(child->get_state());
03232
03233 Texture *result = r_find_texture(child, next_state, glob);
03234 if (result != (Texture *)NULL) {
03235 return result;
03236 }
03237 }
03238
03239 return NULL;
03240 }
03241
03242
03243
03244
03245
03246
03247 void NodePath::
03248 r_find_all_textures(PandaNode *node, const RenderState *state,
03249 NodePath::Textures &textures) const {
03250 if (node->is_geom_node()) {
03251 GeomNode *gnode;
03252 DCAST_INTO_V(gnode, node);
03253
03254 int num_geoms = gnode->get_num_geoms();
03255 for (int i = 0; i < num_geoms; i++) {
03256 CPT(RenderState) geom_state =
03257 state->compose(gnode->get_geom_state(i));
03258
03259
03260 const RenderAttrib *attrib =
03261 geom_state->get_attrib(TextureAttrib::get_class_type());
03262 if (attrib != (const RenderAttrib *)NULL) {
03263 const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
03264 Texture *texture = ta->get_texture();
03265 if (texture != (Texture *)NULL) {
03266 textures.insert(texture);
03267 }
03268 }
03269 }
03270 }
03271
03272
03273 PandaNode::Children cr = node->get_children();
03274 int num_children = cr.get_num_children();
03275 for (int i = 0; i < num_children; i++) {
03276 PandaNode *child = cr.get_child(i);
03277 CPT(RenderState) next_state = state->compose(child->get_state());
03278 r_find_all_textures(child, next_state, textures);
03279 }
03280 }
03281
03282
03283
03284
03285
03286
03287 void NodePath::
03288 r_prepare_scene(PandaNode *node, const RenderState *state,
03289 GraphicsStateGuardianBase *gsg, bool do_retained_mode) {
03290 if (node->is_geom_node()) {
03291 GeomNode *gnode;
03292 DCAST_INTO_V(gnode, node);
03293
03294
03295
03296
03297
03298
03299
03300
03301 int num_geoms = gnode->get_num_geoms();
03302 for (int i = 0; i < num_geoms; i++) {
03303 CPT(RenderState) geom_state = state->compose(gnode->get_geom_state(i));
03304 const RenderAttrib *attrib =
03305 geom_state->get_attrib(TextureAttrib::get_class_type());
03306 if (attrib != (const RenderAttrib *)NULL) {
03307 const TextureAttrib *ta;
03308 DCAST_INTO_V(ta, attrib);
03309 Texture *texture = ta->get_texture();
03310 if (texture != (Texture *)NULL) {
03311 texture->prepare(gsg);
03312 }
03313 }
03314 }
03315 }
03316
03317 int num_children = node->get_num_children();
03318 for (int i = 0; i < num_children; i++) {
03319 PandaNode *child = node->get_child(i);
03320 CPT(RenderState) child_state = state->compose(child->get_state());
03321 r_prepare_scene(child, child_state, gsg, do_retained_mode);
03322 }
03323 }