Panda3D
|
00001 // Filename: textureAttrib.cxx 00002 // Created by: drose (21Feb02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 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 // Function: TextureAttrib::make 00033 // Access: Published, Static 00034 // Description: Constructs a new TextureAttrib object suitable for 00035 // rendering the indicated texture onto geometry, using 00036 // the default TextureStage. 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 // Function: TextureAttrib::make_off 00045 // Access: Published, Static 00046 // Description: Constructs a new TextureAttrib object suitable for 00047 // rendering untextured geometry. 00048 //////////////////////////////////////////////////////////////////// 00049 CPT(RenderAttrib) TextureAttrib:: 00050 make_off() { 00051 return make_all_off(); 00052 } 00053 00054 //////////////////////////////////////////////////////////////////// 00055 // Function: TextureAttrib::make 00056 // Access: Published, Static 00057 // Description: Constructs a new TextureAttrib object that does 00058 // nothing. 00059 //////////////////////////////////////////////////////////////////// 00060 CPT(RenderAttrib) TextureAttrib:: 00061 make() { 00062 // We make it a special case and store a pointer to the empty attrib 00063 // forever once we find it the first time, as an optimization. 00064 if (_empty_attrib == (RenderAttrib *)NULL) { 00065 _empty_attrib = return_new(new TextureAttrib); 00066 } 00067 00068 return _empty_attrib; 00069 } 00070 00071 //////////////////////////////////////////////////////////////////// 00072 // Function: TextureAttrib::make_all_off 00073 // Access: Published, Static 00074 // Description: Constructs a new TextureAttrib object that turns off 00075 // all stages (and hence disables texturing). 00076 //////////////////////////////////////////////////////////////////// 00077 CPT(RenderAttrib) TextureAttrib:: 00078 make_all_off() { 00079 // We make it a special case and store a pointer to the off attrib 00080 // forever once we find it the first time, as an optimization. 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 // Function: TextureAttrib::make_default 00092 // Access: Published, Static 00093 // Description: Returns a RenderAttrib that corresponds to whatever 00094 // the standard default properties for render attributes 00095 // of this type ought to be. 00096 //////////////////////////////////////////////////////////////////// 00097 CPT(RenderAttrib) TextureAttrib:: 00098 make_default() { 00099 return make(); 00100 } 00101 00102 00103 //////////////////////////////////////////////////////////////////// 00104 // Function: TextureAttrib::find_on_stage 00105 // Access: Published 00106 // Description: Returns the index number of the indicated 00107 // TextureStage within the list of on_stages, or -1 if 00108 // the indicated stage is not listed. 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 // Function: TextureAttrib::add_on_stage 00122 // Access: Published 00123 // Description: Returns a new TextureAttrib, just like this one, but 00124 // with the indicated stage added to the list of stages 00125 // turned on by this attrib. 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 // We now need to re-sort the attrib list. 00137 attrib->_sort_seq = UpdateSeq::old(); 00138 attrib->_filtered_seq = UpdateSeq::old(); 00139 00140 return return_new(attrib); 00141 } 00142 00143 //////////////////////////////////////////////////////////////////// 00144 // Function: TextureAttrib::remove_on_stage 00145 // Access: Published 00146 // Description: Returns a new TextureAttrib, just like this one, but 00147 // with the indicated stage removed from the list of 00148 // stages turned on by this attrib. 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 // Function: TextureAttrib::add_off_stage 00167 // Access: Published 00168 // Description: Returns a new TextureAttrib, just like this one, but 00169 // with the indicated stage added to the list of stages 00170 // turned off by this attrib. 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 // Also ensure it is removed from the on_stages list. 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 // Function: TextureAttrib::remove_off_stage 00193 // Access: Published 00194 // Description: Returns a new TextureAttrib, just like this one, but 00195 // with the indicated stage removed from the list of 00196 // stages turned off by this attrib. 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 // Function: TextureAttrib::unify_texture_stages 00207 // Access: Published 00208 // Description: Returns a new TextureAttrib, just like this one, but 00209 // with any included TextureAttribs that happen to have 00210 // the same name as the given object replaced with the 00211 // object. 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 // Function: TextureAttrib::filter_to_max 00260 // Access: Public 00261 // Description: Returns a new TextureAttrib, very much like this one, 00262 // but with the number of on_stages reduced to be no 00263 // more than max_texture_stages. The number of 00264 // off_stages in the new TextureAttrib is undefined. 00265 //////////////////////////////////////////////////////////////////// 00266 CPT(TextureAttrib) TextureAttrib:: 00267 filter_to_max(int max_texture_stages) const { 00268 if ((int)_on_stages.size() <= max_texture_stages) { 00269 // Trivial case: this TextureAttrib qualifies. 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 // Easy case: we have already computed this for this particular 00282 // TextureAttrib. 00283 return (*fi).second; 00284 } 00285 00286 // Harder case: we have to compute it now. We must choose the n 00287 // stages with the highest priority in our list of stages. In the 00288 // case of equal priority, we prefer the stage with the lower sort. 00289 check_sorted(); 00290 00291 RenderStages priority_stages = _render_stages; 00292 00293 // This sort function uses the STL function object defined above. 00294 sort(priority_stages.begin(), priority_stages.end(), 00295 CompareTextureStagePriorities()); 00296 00297 // Now lop off all of the stages after the first max_texture_stages. 00298 priority_stages.erase(priority_stages.begin() + max_texture_stages, 00299 priority_stages.end()); 00300 00301 // And create a new attrib reflecting these stages. 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 // Finally, record this newly-created attrib in the map for next 00314 // time. 00315 00316 // TODO: if new_attrib == this, have we just created a circular 00317 // reference count? Whoops! Fix this! 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 // Function: TextureAttrib::lower_attrib_can_override 00326 // Access: Public, Virtual 00327 // Description: Intended to be overridden by derived RenderAttrib 00328 // types to specify how two consecutive RenderAttrib 00329 // objects of the same type interact. 00330 // 00331 // This should return false if a RenderAttrib on a 00332 // higher node will compose into a RenderAttrib on a 00333 // lower node that has a higher override value, or false 00334 // if the lower RenderAttrib will completely replace the 00335 // state. 00336 // 00337 // The default behavior is false: normally, a 00338 // RenderAttrib in the graph cannot completely override 00339 // a RenderAttrib above it, regardless of its override 00340 // value--instead, the two attribs are composed. But 00341 // for some kinds of RenderAttribs, it is useful to 00342 // allow this kind of override. 00343 // 00344 // This method only handles the one special case of a 00345 // lower RenderAttrib with a higher override value. If 00346 // the higher RenderAttrib has a higher override value, 00347 // it always completely overrides. And if both 00348 // RenderAttribs have the same override value, they are 00349 // always composed. 00350 //////////////////////////////////////////////////////////////////// 00351 bool TextureAttrib:: 00352 lower_attrib_can_override() const { 00353 // A TextureAttrib doesn't compose through an override. Normally, 00354 // there won't be a scene-graph override on a TextureAttrib anyway, 00355 // since the NodePath::set_texture() override is applied to the 00356 // per-TextureStage override value. But there might be a 00357 // scene-graph override if NodePath::adjust_all_priorities() is 00358 // used, and in this case, we'd like for it to stick. 00359 return true; 00360 } 00361 00362 //////////////////////////////////////////////////////////////////// 00363 // Function: TextureAttrib::output 00364 // Access: Public, Virtual 00365 // Description: 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 // Function: TextureAttrib::has_cull_callback 00421 // Access: Public, Virtual 00422 // Description: Should be overridden by derived classes to return 00423 // true if cull_callback() has been defined. Otherwise, 00424 // returns false to indicate cull_callback() does not 00425 // need to be called for this node during the cull 00426 // traversal. 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 // Function: TextureAttrib::cull_callback 00443 // Access: Public, Virtual 00444 // Description: If has_cull_callback() returns true, this function 00445 // will be called during the cull traversal to perform 00446 // any additional operations that should be performed at 00447 // cull time. 00448 // 00449 // This is called each time the RenderAttrib is 00450 // discovered applied to a Geom in the traversal. It 00451 // should return true if the Geom is visible, false if 00452 // it should be omitted. 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 // Function: TextureAttrib::compare_to_impl 00469 // Access: Protected, Virtual 00470 // Description: Intended to be overridden by derived TextureAttrib 00471 // types to return a unique number indicating whether 00472 // this TextureAttrib is equivalent to the other one. 00473 // 00474 // This should return 0 if the two TextureAttrib objects 00475 // are equivalent, a number less than zero if this one 00476 // should be sorted before the other one, and a number 00477 // greater than zero otherwise. 00478 // 00479 // This will only be called with two TextureAttrib 00480 // objects whose get_type() functions return the same. 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 // Finally, ensure that the set of off stages is the same. 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 // Function: TextureAttrib::get_hash_impl 00569 // Access: Protected, Virtual 00570 // Description: Intended to be overridden by derived RenderAttrib 00571 // types to return a unique hash for these particular 00572 // properties. RenderAttribs that compare the same with 00573 // compare_to_impl(), above, should return the same 00574 // hash; RenderAttribs that compare differently should 00575 // return a different hash. 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 // This bool value goes here, between the two lists, to 00593 // differentiate between the two. 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 // Function: TextureAttrib::compose_impl 00608 // Access: Protected, Virtual 00609 // Description: Intended to be overridden by derived RenderAttrib 00610 // types to specify how two consecutive RenderAttrib 00611 // objects of the same type interact. 00612 // 00613 // This should return the result of applying the other 00614 // RenderAttrib to a node in the scene graph below this 00615 // RenderAttrib, which was already applied. In most 00616 // cases, the result is the same as the other 00617 // RenderAttrib (that is, a subsequent RenderAttrib 00618 // completely replaces the preceding one). On the other 00619 // hand, some kinds of RenderAttrib (for instance, 00620 // ColorTransformAttrib) might combine in meaningful 00621 // ways. 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 // If the other type turns off all stages, it doesn't matter what 00630 // we are. 00631 return ta; 00632 } 00633 00634 // This is a three-way merge between ai, bi, and ci, except that bi 00635 // and ci should have no intersection and therefore needn't be 00636 // compared to each other. 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 // Create a new TextureAttrib that will hold the result. 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 // Here is a stage that we have in the original, which is not 00650 // present in the secondary. 00651 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); 00652 ++ai; 00653 00654 } else if ((*ci)._stage < (*ai)._stage) { 00655 // Here is a stage that is turned off in the secondary, but 00656 // was not present in the original. 00657 ++ci; 00658 00659 } else { // (*ci)._stage == (*ai)._stage 00660 // Here is a stage that is turned off in the secondary, and 00661 // was present in the original. 00662 if ((*ai)._override > (*ci)._override) { 00663 // But never mind, keep it anyway. 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 // Here is a new stage we have in the secondary, that was not 00673 // present in the original. 00674 attrib->_on_stages.insert(attrib->_on_stages.end(), *bi); 00675 ++bi; 00676 00677 } else { // (*bi)._stage == (*ai)._stage 00678 // Here is a stage we have in both. 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 // Here is a stage that we have in the original, which is not 00692 // present in the secondary. 00693 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); 00694 ++ai; 00695 00696 } else if ((*bi)._stage < (*ai)._stage) { 00697 // Here is a new stage we have in the secondary, that was not 00698 // present in the original. 00699 attrib->_on_stages.insert(attrib->_on_stages.end(), *bi); 00700 ++bi; 00701 00702 } else { 00703 // Here is a stage we have in both. 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 // Here is a stage that we have in the original, which is not 00717 // present in the secondary. 00718 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); 00719 ++ai; 00720 00721 } else if ((*ci)._stage < (*ai)._stage) { 00722 // Here is a stage that is turned off in the secondary, but 00723 // was not present in the original. 00724 ++ci; 00725 00726 } else { // (*ci)._stage == (*ai)._stage 00727 // Here is a stage that is turned off in the secondary, and 00728 // was present in the original. 00729 if ((*ai)._override > (*ci)._override) { 00730 // But never mind, keep it anyway. 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 // Function: TextureAttrib::invert_compose_impl 00757 // Access: Protected, Virtual 00758 // Description: Intended to be overridden by derived RenderAttrib 00759 // types to specify how two consecutive RenderAttrib 00760 // objects of the same type interact. 00761 // 00762 // See invert_compose() and compose_impl(). 00763 //////////////////////////////////////////////////////////////////// 00764 CPT(RenderAttrib) TextureAttrib:: 00765 invert_compose_impl(const RenderAttrib *other) const { 00766 // I think in this case the other attrib always wins. Maybe this 00767 // needs a bit more thought. It's hard to imagine that it's even 00768 // important to compute this properly. 00769 return other; 00770 } 00771 00772 //////////////////////////////////////////////////////////////////// 00773 // Function: TextureAttrib::get_auto_shader_attrib_impl 00774 // Access: Protected, Virtual 00775 // Description: 00776 //////////////////////////////////////////////////////////////////// 00777 CPT(RenderAttrib) TextureAttrib:: 00778 get_auto_shader_attrib_impl(const RenderState *state) const { 00779 return this; 00780 } 00781 00782 //////////////////////////////////////////////////////////////////// 00783 // Function: TextureAttrib::register_with_read_factory 00784 // Access: Public, Static 00785 // Description: Tells the BamReader how to create objects of type 00786 // TextureAttrib. 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 // Function: TextureAttrib::write_datagram 00795 // Access: Public, Virtual 00796 // Description: Writes the contents of this object to the datagram 00797 // for shipping out to a Bam file. 00798 //////////////////////////////////////////////////////////////////// 00799 void TextureAttrib:: 00800 write_datagram(BamWriter *manager, Datagram &dg) { 00801 RenderAttrib::write_datagram(manager, dg); 00802 00803 // Write the off_stages information 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 // Write the on_stages information 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 // Function: TextureAttrib::complete_pointers 00829 // Access: Public, Virtual 00830 // Description: Receives an array of pointers, one for each time 00831 // manager->read_pointer() was called in fillin(). 00832 // Returns the number of pointers processed. 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 // Filter the TextureStage through the TextureStagePool. 00847 PT(TextureStage) ts = DCAST(TextureStage, p_list[pi++]); 00848 ts = TextureStagePool::get_stage(ts); 00849 00850 // The Texture pointer filters itself through the TexturePool, so 00851 // we don't have to do anything special here. 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 // If we couldn't load a texture pointer, turn off that 00862 // particular texture stage. 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 // Function: TextureAttrib::make_from_bam 00876 // Access: Protected, Static 00877 // Description: This function is called by the BamReader's factory 00878 // when a new object of type TextureAttrib is encountered 00879 // in the Bam file. It should create the TextureAttrib 00880 // and extract its information from the file. 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 // Function: TextureAttrib::fillin 00896 // Access: Protected 00897 // Description: This internal function is called by make_from_bam to 00898 // read in all of the relevant data from the BamFile for 00899 // the new TextureAttrib. 00900 //////////////////////////////////////////////////////////////////// 00901 void TextureAttrib:: 00902 fillin(DatagramIterator &scan, BamReader *manager) { 00903 RenderAttrib::fillin(scan, manager); 00904 00905 // read the _off_stages data. 00906 _off_all_stages = scan.get_bool(); 00907 int num_off_stages = scan.get_uint16(); 00908 00909 // Push back a NULL pointer for each off TextureStage for now, until 00910 // we get the actual list of pointers later in complete_pointers(). 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 // Read the _on_stages data. 00919 int num_on_stages = scan.get_uint16(); 00920 00921 // Push back a NULL pointer for each off TextureStage and Texture 00922 // for now, until we get the actual list of pointers later in 00923 // complete_pointers(). 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 // Function: TextureAttrib::sort_on_stages 00948 // Access: Private 00949 // Description: Sorts the list of stages so that they are listed in 00950 // render order. Also clears the _filtered map and 00951 // recalculates the list of fixed-function stages. 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 // This pair of lines will get the next consecutive texcoord index 00970 // number if this is the first time we have referenced this 00971 // particular texcoord name; otherwise, it will return the same 00972 // index number it returned before. 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 // We'd like to clear the _filtered map, in case the TextureStage 00988 // priority values have changed as well, but we can't do that here: 00989 // it's too dangerous. Clearing _filtered might cause 00990 // TextureAttribs to be deleted, and hence removed from the map that 00991 // we might be in the middle of traversing! 00992 00993 _sort_seq = TextureStage::get_sort_seq(); 00994 }