00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "textureAttrib.h"
00016 #include "graphicsStateGuardianBase.h"
00017 #include "internalName.h"
00018 #include "bamReader.h"
00019 #include "bamWriter.h"
00020 #include "datagram.h"
00021 #include "datagramIterator.h"
00022 #include "dcast.h"
00023 #include "textureStagePool.h"
00024
00025 CPT(RenderAttrib) TextureAttrib::_empty_attrib;
00026 CPT(RenderAttrib) TextureAttrib::_all_off_attrib;
00027 TypeHandle TextureAttrib::_type_handle;
00028 int TextureAttrib::_attrib_slot;
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 CPT(RenderAttrib) TextureAttrib::
00039 make(Texture *texture) {
00040 return DCAST(TextureAttrib, make())->add_on_stage(TextureStage::get_default(), texture);
00041 }
00042
00043
00044
00045
00046
00047
00048
00049 CPT(RenderAttrib) TextureAttrib::
00050 make_off() {
00051 return make_all_off();
00052 }
00053
00054
00055
00056
00057
00058
00059
00060 CPT(RenderAttrib) TextureAttrib::
00061 make() {
00062
00063
00064 if (_empty_attrib == (RenderAttrib *)NULL) {
00065 _empty_attrib = return_new(new TextureAttrib);
00066 }
00067
00068 return _empty_attrib;
00069 }
00070
00071
00072
00073
00074
00075
00076
00077 CPT(RenderAttrib) TextureAttrib::
00078 make_all_off() {
00079
00080
00081 if (_all_off_attrib == (RenderAttrib *)NULL) {
00082 TextureAttrib *attrib = new TextureAttrib;
00083 attrib->_off_all_stages = true;
00084 _all_off_attrib = return_new(attrib);
00085 }
00086
00087 return _all_off_attrib;
00088 }
00089
00090
00091
00092
00093
00094
00095
00096
00097 CPT(RenderAttrib) TextureAttrib::
00098 make_default() {
00099 return make();
00100 }
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110 int TextureAttrib::
00111 find_on_stage(const TextureStage *stage) const {
00112 Stages::const_iterator si = _on_stages.find(StageNode(stage));
00113 if (si != _on_stages.end()) {
00114 return (int)(si - _on_stages.begin());
00115 }
00116
00117 return -1;
00118 }
00119
00120
00121
00122
00123
00124
00125
00126
00127 CPT(RenderAttrib) TextureAttrib::
00128 add_on_stage(TextureStage *stage, Texture *tex, int override) const {
00129 TextureAttrib *attrib = new TextureAttrib(*this);
00130 Stages::iterator si = attrib->_on_stages.insert(StageNode(stage)).first;
00131 (*si)._override = override;
00132 (*si)._texture = tex;
00133 (*si)._implicit_sort = attrib->_next_implicit_sort;
00134 ++(attrib->_next_implicit_sort);
00135
00136
00137 attrib->_sort_seq = UpdateSeq::old();
00138 attrib->_filtered_seq = UpdateSeq::old();
00139
00140 return return_new(attrib);
00141 }
00142
00143
00144
00145
00146
00147
00148
00149
00150 CPT(RenderAttrib) TextureAttrib::
00151 remove_on_stage(TextureStage *stage) const {
00152 TextureAttrib *attrib = new TextureAttrib(*this);
00153
00154 Stages::iterator si = attrib->_on_stages.find(StageNode(stage));
00155 if (si != attrib->_on_stages.end()) {
00156 attrib->_on_stages.erase(si);
00157
00158 attrib->_sort_seq = UpdateSeq::old();
00159 attrib->_filtered_seq = UpdateSeq::old();
00160 }
00161
00162 return return_new(attrib);
00163 }
00164
00165
00166
00167
00168
00169
00170
00171
00172 CPT(RenderAttrib) TextureAttrib::
00173 add_off_stage(TextureStage *stage, int override) const {
00174 TextureAttrib *attrib = new TextureAttrib(*this);
00175 if (!_off_all_stages) {
00176 StageNode sn(stage);
00177 Stages::iterator sfi = attrib->_off_stages.insert(sn).first;
00178 (*sfi)._override = override;
00179
00180
00181 Stages::iterator si = attrib->_on_stages.find(sn);
00182 if (si != attrib->_on_stages.end()) {
00183 attrib->_on_stages.erase(si);
00184 attrib->_sort_seq = UpdateSeq::old();
00185 attrib->_filtered_seq = UpdateSeq::old();
00186 }
00187 }
00188 return return_new(attrib);
00189 }
00190
00191
00192
00193
00194
00195
00196
00197
00198 CPT(RenderAttrib) TextureAttrib::
00199 remove_off_stage(TextureStage *stage) const {
00200 TextureAttrib *attrib = new TextureAttrib(*this);
00201 attrib->_off_stages.erase(StageNode(stage));
00202 return return_new(attrib);
00203 }
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213 CPT(RenderAttrib) TextureAttrib::
00214 unify_texture_stages(TextureStage *stage) const {
00215 PT(TextureAttrib) attrib = new TextureAttrib;
00216
00217 attrib->_off_all_stages = _off_all_stages;
00218 bool any_changed = false;
00219
00220 Stages::const_iterator si;
00221 for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
00222 TextureStage *this_stage = (*si)._stage;
00223
00224 if (this_stage->get_name() == stage->get_name()) {
00225 this_stage = stage;
00226 any_changed = true;
00227 }
00228
00229 Stages::iterator osi = attrib->_on_stages.insert(StageNode(this_stage)).first;
00230 (*osi)._texture = (*si)._texture;
00231 (*osi)._ff_tc_index = (*si)._ff_tc_index;
00232 (*osi)._implicit_sort = (*si)._implicit_sort;
00233 (*osi)._override = (*si)._override;
00234 }
00235
00236 attrib->_next_implicit_sort = _next_implicit_sort;
00237
00238 Stages::const_iterator fsi;
00239 for (fsi = _off_stages.begin(); fsi != _off_stages.end(); ++fsi) {
00240 TextureStage *this_stage = (*fsi)._stage;
00241
00242 if (this_stage != stage &&
00243 this_stage->get_name() == stage->get_name()) {
00244 this_stage = stage;
00245 any_changed = true;
00246 }
00247
00248 attrib->_off_stages.insert(StageNode(this_stage));
00249 }
00250
00251 if (!any_changed) {
00252 return this;
00253 }
00254
00255 return return_new(attrib);
00256 }
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266 CPT(TextureAttrib) TextureAttrib::
00267 filter_to_max(int max_texture_stages) const {
00268 if ((int)_on_stages.size() <= max_texture_stages) {
00269
00270 return this;
00271 }
00272
00273 if (_filtered_seq != TextureStage::get_sort_seq()) {
00274 ((TextureAttrib *)this)->_filtered.clear();
00275 ((TextureAttrib *)this)->_filtered_seq = TextureStage::get_sort_seq();
00276 }
00277
00278 Filtered::const_iterator fi;
00279 fi = _filtered.find(max_texture_stages);
00280 if (fi != _filtered.end()) {
00281
00282
00283 return (*fi).second;
00284 }
00285
00286
00287
00288
00289 check_sorted();
00290
00291 RenderStages priority_stages = _render_stages;
00292
00293
00294 sort(priority_stages.begin(), priority_stages.end(),
00295 CompareTextureStagePriorities());
00296
00297
00298 priority_stages.erase(priority_stages.begin() + max_texture_stages,
00299 priority_stages.end());
00300
00301
00302 PT(TextureAttrib) attrib = new TextureAttrib;
00303
00304 RenderStages::const_iterator ri;
00305 for (ri = priority_stages.begin(); ri != priority_stages.end(); ++ri) {
00306 attrib->_on_stages.insert(*(*ri));
00307 }
00308
00309 attrib->_next_implicit_sort = _next_implicit_sort;
00310
00311 CPT(RenderAttrib) new_attrib = return_new(attrib);
00312
00313
00314
00315
00316
00317
00318
00319 CPT(TextureAttrib) tex_attrib = (const TextureAttrib *)new_attrib.p();
00320 ((TextureAttrib *)this)->_filtered[max_texture_stages] = tex_attrib;
00321 return tex_attrib;
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351 bool TextureAttrib::
00352 lower_attrib_can_override() const {
00353
00354
00355
00356
00357
00358
00359 return true;
00360 }
00361
00362
00363
00364
00365
00366
00367 void TextureAttrib::
00368 output(ostream &out) const {
00369 check_sorted();
00370
00371 out << get_type() << ":";
00372 if (_off_stages.empty()) {
00373 if (_on_stages.empty()) {
00374 if (_off_all_stages) {
00375 out << "all off";
00376 } else {
00377 out << "identity";
00378 }
00379 } else {
00380 if (_off_all_stages) {
00381 out << "set";
00382 } else {
00383 out << "on";
00384 }
00385 }
00386
00387 } else {
00388 out << "off";
00389 Stages::const_iterator fi;
00390 for (fi = _off_stages.begin(); fi != _off_stages.end(); ++fi) {
00391 TextureStage *stage = (*fi)._stage;
00392 out << " " << stage->get_name();
00393 if ((*fi)._override != 0) {
00394 out << "^" << (*fi)._override;
00395 }
00396 }
00397
00398 if (!_on_stages.empty()) {
00399 out << " on";
00400 }
00401 }
00402
00403 RenderStages::const_iterator ri;
00404 for (ri = _render_stages.begin(); ri != _render_stages.end(); ++ri) {
00405 const StageNode &sn = *(*ri);
00406 TextureStage *stage = sn._stage;
00407 Texture *tex = sn._texture;
00408 if (tex != NULL) {
00409 out << " " << stage->get_name() << ":" << tex->get_name();
00410 } else {
00411 out << " " << stage->get_name();
00412 }
00413 if (sn._override != 0) {
00414 out << "^" << sn._override;
00415 }
00416 }
00417 }
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428 bool TextureAttrib::
00429 has_cull_callback() const {
00430 Stages::const_iterator si;
00431 for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
00432 Texture *texture = (*si)._texture;
00433 if (texture->has_cull_callback()) {
00434 return true;
00435 }
00436 }
00437
00438 return false;
00439 }
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454 bool TextureAttrib::
00455 cull_callback(CullTraverser *trav, const CullTraverserData &data) const {
00456 Stages::const_iterator si;
00457 for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
00458 Texture *texture = (*si)._texture;
00459 if (!texture->cull_callback(trav, data)) {
00460 return false;
00461 }
00462 }
00463
00464 return true;
00465 }
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482 int TextureAttrib::
00483 compare_to_impl(const RenderAttrib *other) const {
00484 const TextureAttrib *ta;
00485 DCAST_INTO_R(ta, other, 0);
00486
00487 if (_off_all_stages != ta->_off_all_stages) {
00488 return (int)_off_all_stages - (int)ta->_off_all_stages;
00489 }
00490
00491 Stages::const_iterator si = _on_stages.begin();
00492 Stages::const_iterator osi = ta->_on_stages.begin();
00493
00494 while (si != _on_stages.end() && osi != ta->_on_stages.end()) {
00495 TextureStage *stage = (*si)._stage;
00496 TextureStage *other_stage = (*osi)._stage;
00497
00498 if (stage != other_stage) {
00499 return stage < other_stage ? -1 : 1;
00500 }
00501
00502 Texture *texture = (*si)._texture;
00503 Texture *other_texture = (*osi)._texture;
00504
00505 if (texture != other_texture) {
00506 return texture < other_texture ? -1 : 1;
00507 }
00508
00509 int implicit_sort = (*si)._implicit_sort;
00510 int other_implicit_sort = (*osi)._implicit_sort;
00511
00512 if (implicit_sort != other_implicit_sort) {
00513 return implicit_sort < other_implicit_sort ? -1 : 1;
00514 }
00515
00516 int override = (*si)._override;
00517 int other_override = (*osi)._override;
00518
00519 if (override != other_override) {
00520 return override < other_override ? -1 : 1;
00521 }
00522
00523 ++si;
00524 ++osi;
00525 }
00526
00527 if (si != _on_stages.end()) {
00528 return 1;
00529 }
00530 if (osi != ta->_on_stages.end()) {
00531 return -1;
00532 }
00533
00534
00535 Stages::const_iterator fi = _off_stages.begin();
00536 Stages::const_iterator ofi = ta->_off_stages.begin();
00537
00538 while (fi != _off_stages.end() && ofi != ta->_off_stages.end()) {
00539 TextureStage *stage = (*fi)._stage;
00540 TextureStage *other_stage = (*ofi)._stage;
00541
00542 if (stage != other_stage) {
00543 return stage < other_stage ? -1 : 1;
00544 }
00545
00546 int override = (*fi)._override;
00547 int other_override = (*ofi)._override;
00548
00549 if (override != other_override) {
00550 return override < other_override ? -1 : 1;
00551 }
00552
00553 ++fi;
00554 ++ofi;
00555 }
00556
00557 if (fi != _off_stages.end()) {
00558 return 1;
00559 }
00560 if (ofi != ta->_off_stages.end()) {
00561 return -1;
00562 }
00563
00564 return 0;
00565 }
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 size_t TextureAttrib::
00578 get_hash_impl() const {
00579 check_sorted();
00580
00581 size_t hash = 0;
00582 Stages::const_iterator si;
00583 for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
00584 const StageNode &sn = (*si);
00585
00586 hash = pointer_hash::add_hash(hash, sn._stage);
00587 hash = pointer_hash::add_hash(hash, sn._texture);
00588 hash = int_hash::add_hash(hash, (int)sn._implicit_sort);
00589 hash = int_hash::add_hash(hash, sn._override);
00590 }
00591
00592
00593
00594 hash = int_hash::add_hash(hash, (int)_off_all_stages);
00595
00596 for (si = _off_stages.begin(); si != _off_stages.end(); ++si) {
00597 const StageNode &sn = (*si);
00598
00599 hash = pointer_hash::add_hash(hash, sn._stage);
00600 hash = int_hash::add_hash(hash, sn._override);
00601 }
00602
00603 return hash;
00604 }
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623 CPT(RenderAttrib) TextureAttrib::
00624 compose_impl(const RenderAttrib *other) const {
00625 const TextureAttrib *ta;
00626 DCAST_INTO_R(ta, other, 0);
00627
00628 if (ta->_off_all_stages) {
00629
00630
00631 return ta;
00632 }
00633
00634
00635
00636
00637 Stages::const_iterator ai = _on_stages.begin();
00638 Stages::const_iterator bi = ta->_on_stages.begin();
00639 Stages::const_iterator ci = ta->_off_stages.begin();
00640
00641
00642 TextureAttrib *attrib = new TextureAttrib;
00643
00644 while (ai != _on_stages.end() &&
00645 bi != ta->_on_stages.end() &&
00646 ci != ta->_off_stages.end()) {
00647 if ((*ai)._stage < (*bi)._stage) {
00648 if ((*ai)._stage < (*ci)._stage) {
00649
00650
00651 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
00652 ++ai;
00653
00654 } else if ((*ci)._stage < (*ai)._stage) {
00655
00656
00657 ++ci;
00658
00659 } else {
00660
00661
00662 if ((*ai)._override > (*ci)._override) {
00663
00664 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
00665 }
00666
00667 ++ai;
00668 ++ci;
00669 }
00670
00671 } else if ((*bi)._stage < (*ai)._stage) {
00672
00673
00674 attrib->_on_stages.insert(attrib->_on_stages.end(), *bi);
00675 ++bi;
00676
00677 } else {
00678
00679 if ((*ai)._override > (*bi)._override) {
00680 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
00681 } else {
00682 attrib->_on_stages.insert(attrib->_on_stages.end(), *bi);
00683 }
00684 ++ai;
00685 ++bi;
00686 }
00687 }
00688
00689 while (ai != _on_stages.end() && bi != ta->_on_stages.end()) {
00690 if ((*ai)._stage < (*bi)._stage) {
00691
00692
00693 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
00694 ++ai;
00695
00696 } else if ((*bi)._stage < (*ai)._stage) {
00697
00698
00699 attrib->_on_stages.insert(attrib->_on_stages.end(), *bi);
00700 ++bi;
00701
00702 } else {
00703
00704 if ((*ai)._override > (*bi)._override) {
00705 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
00706 } else {
00707 attrib->_on_stages.insert(attrib->_on_stages.end(), *bi);
00708 }
00709 ++ai;
00710 ++bi;
00711 }
00712 }
00713
00714 while (ai != _on_stages.end() && ci != ta->_off_stages.end()) {
00715 if ((*ai)._stage < (*ci)._stage) {
00716
00717
00718 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
00719 ++ai;
00720
00721 } else if ((*ci)._stage < (*ai)._stage) {
00722
00723
00724 ++ci;
00725
00726 } else {
00727
00728
00729 if ((*ai)._override > (*ci)._override) {
00730
00731 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
00732 }
00733 ++ai;
00734 ++ci;
00735 }
00736 }
00737
00738 while (ai != _on_stages.end()) {
00739 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai);
00740 ++ai;
00741 }
00742
00743 while (bi != ta->_on_stages.end()) {
00744 attrib->_on_stages.insert(attrib->_on_stages.end(), *bi);
00745 ++bi;
00746 }
00747
00748 attrib->_next_implicit_sort = _next_implicit_sort + ta->_next_implicit_sort;
00749 attrib->_sort_seq = UpdateSeq::old();
00750 attrib->_filtered_seq = UpdateSeq::old();
00751
00752 return return_new(attrib);
00753 }
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764 CPT(RenderAttrib) TextureAttrib::
00765 invert_compose_impl(const RenderAttrib *other) const {
00766
00767
00768
00769 return other;
00770 }
00771
00772
00773
00774
00775
00776
00777 CPT(RenderAttrib) TextureAttrib::
00778 get_auto_shader_attrib_impl(const RenderState *state) const {
00779 return this;
00780 }
00781
00782
00783
00784
00785
00786
00787
00788 void TextureAttrib::
00789 register_with_read_factory() {
00790 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00791 }
00792
00793
00794
00795
00796
00797
00798
00799 void TextureAttrib::
00800 write_datagram(BamWriter *manager, Datagram &dg) {
00801 RenderAttrib::write_datagram(manager, dg);
00802
00803
00804 dg.add_bool(_off_all_stages);
00805 dg.add_uint16(get_num_off_stages());
00806 Stages::const_iterator fi;
00807 for (fi = _off_stages.begin(); fi != _off_stages.end(); ++fi) {
00808 TextureStage *stage = (*fi)._stage;
00809 manager->write_pointer(dg, stage);
00810 }
00811
00812
00813 dg.add_uint16(get_num_on_stages());
00814 Stages::const_iterator si;
00815 for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
00816 TextureStage *stage = (*si)._stage;
00817 Texture *tex = (*si)._texture;
00818 nassertv(tex != (Texture *)NULL);
00819
00820 manager->write_pointer(dg, stage);
00821 manager->write_pointer(dg, tex);
00822 dg.add_uint16((*si)._implicit_sort);
00823 dg.add_int32((*si)._override);
00824 }
00825 }
00826
00827
00828
00829
00830
00831
00832
00833
00834 int TextureAttrib::
00835 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00836 int pi = RenderAttrib::complete_pointers(p_list, manager);
00837
00838 Stages::iterator ci;
00839 for (ci = _off_stages.begin(); ci != _off_stages.end(); ++ci) {
00840 TextureStage *ts = DCAST(TextureStage, p_list[pi++]);
00841 *ci = StageNode(ts);
00842 }
00843
00844 size_t sni = 0;
00845 while (sni < _on_stages.size()) {
00846
00847 PT(TextureStage) ts = DCAST(TextureStage, p_list[pi++]);
00848 ts = TextureStagePool::get_stage(ts);
00849
00850
00851
00852 Texture *tex = DCAST(Texture, p_list[pi++]);
00853
00854 if (tex != (Texture *)NULL) {
00855 StageNode &sn = _on_stages[sni];
00856 sn._stage = ts;
00857 sn._texture = tex;
00858 ++sni;
00859
00860 } else {
00861
00862
00863 _off_stages.push_back(StageNode(ts));
00864 _on_stages.erase(_on_stages.begin() + sni);
00865 }
00866 }
00867 _on_stages.sort();
00868 _sort_seq = UpdateSeq::old();
00869 _filtered_seq = UpdateSeq::old();
00870
00871 return pi;
00872 }
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882 TypedWritable *TextureAttrib::
00883 make_from_bam(const FactoryParams ¶ms) {
00884 TextureAttrib *attrib = new TextureAttrib;
00885 DatagramIterator scan;
00886 BamReader *manager;
00887
00888 parse_params(params, scan, manager);
00889 attrib->fillin(scan, manager);
00890
00891 return attrib;
00892 }
00893
00894
00895
00896
00897
00898
00899
00900
00901 void TextureAttrib::
00902 fillin(DatagramIterator &scan, BamReader *manager) {
00903 RenderAttrib::fillin(scan, manager);
00904
00905
00906 _off_all_stages = scan.get_bool();
00907 int num_off_stages = scan.get_uint16();
00908
00909
00910
00911 int i;
00912 _off_stages.reserve(num_off_stages);
00913 for (i = 0; i < num_off_stages; i++) {
00914 manager->read_pointer(scan);
00915 _off_stages.push_back(StageNode(NULL));
00916 }
00917
00918
00919 int num_on_stages = scan.get_uint16();
00920
00921
00922
00923
00924 _on_stages.reserve(num_on_stages);
00925 _next_implicit_sort = 0;
00926 for (i = 0; i < num_on_stages; i++) {
00927 manager->read_pointer(scan);
00928 manager->read_pointer(scan);
00929 unsigned int implicit_sort;
00930 if (manager->get_file_minor_ver() >= 15) {
00931 implicit_sort = scan.get_uint16();
00932 } else {
00933 implicit_sort = (unsigned int)i;
00934 }
00935 int override = 0;
00936 if (manager->get_file_minor_ver() >= 23) {
00937 override = scan.get_int32();
00938 }
00939
00940 _next_implicit_sort = max(_next_implicit_sort, implicit_sort + 1);
00941 _on_stages.push_back(StageNode(NULL, _next_implicit_sort, override));
00942 ++_next_implicit_sort;
00943 }
00944 }
00945
00946
00947
00948
00949
00950
00951
00952
00953 void TextureAttrib::
00954 sort_on_stages() {
00955 typedef pmap<const InternalName *, int> UsedTexcoordIndex;
00956 UsedTexcoordIndex used_texcoord_index;
00957
00958 _render_stages.clear();
00959 _render_ff_stages.clear();
00960
00961 Stages::iterator si;
00962 for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
00963 StageNode &sn = (*si);
00964 TextureStage *stage = sn._stage;
00965 nassertv(stage != NULL);
00966 if (stage->is_fixed_function()) {
00967 const InternalName *name = stage->get_texcoord_name();
00968
00969
00970
00971
00972
00973 UsedTexcoordIndex::iterator ti = used_texcoord_index.insert(UsedTexcoordIndex::value_type(name, (int)used_texcoord_index.size())).first;
00974 (*si)._ff_tc_index = (*ti).second;
00975
00976 _render_ff_stages.push_back(&sn);
00977 } else {
00978 (*si)._ff_tc_index = -1;
00979 }
00980
00981 _render_stages.push_back(&sn);
00982 }
00983
00984 sort(_render_stages.begin(), _render_stages.end(), CompareTextureStageSort());
00985 sort(_render_ff_stages.begin(), _render_ff_stages.end(), CompareTextureStageSort());
00986
00987
00988
00989
00990
00991
00992
00993 _sort_seq = TextureStage::get_sort_seq();
00994 }