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 CPT(TextureAttrib) tex_attrib = (const TextureAttrib *)new_attrib.p(); 00316 ((TextureAttrib *)this)->_filtered[max_texture_stages] = tex_attrib; 00317 return tex_attrib; 00318 } 00319 00320 //////////////////////////////////////////////////////////////////// 00321 // Function: TextureAttrib::lower_attrib_can_override 00322 // Access: Public, Virtual 00323 // Description: Intended to be overridden by derived RenderAttrib 00324 // types to specify how two consecutive RenderAttrib 00325 // objects of the same type interact. 00326 // 00327 // This should return false if a RenderAttrib on a 00328 // higher node will compose into a RenderAttrib on a 00329 // lower node that has a higher override value, or false 00330 // if the lower RenderAttrib will completely replace the 00331 // state. 00332 // 00333 // The default behavior is false: normally, a 00334 // RenderAttrib in the graph cannot completely override 00335 // a RenderAttrib above it, regardless of its override 00336 // value--instead, the two attribs are composed. But 00337 // for some kinds of RenderAttribs, it is useful to 00338 // allow this kind of override. 00339 // 00340 // This method only handles the one special case of a 00341 // lower RenderAttrib with a higher override value. If 00342 // the higher RenderAttrib has a higher override value, 00343 // it always completely overrides. And if both 00344 // RenderAttribs have the same override value, they are 00345 // always composed. 00346 //////////////////////////////////////////////////////////////////// 00347 bool TextureAttrib:: 00348 lower_attrib_can_override() const { 00349 // A TextureAttrib doesn't compose through an override. Normally, 00350 // there won't be a scene-graph override on a TextureAttrib anyway, 00351 // since the NodePath::set_texture() override is applied to the 00352 // per-TextureStage override value. But there might be a 00353 // scene-graph override if NodePath::adjust_all_priorities() is 00354 // used, and in this case, we'd like for it to stick. 00355 return true; 00356 } 00357 00358 //////////////////////////////////////////////////////////////////// 00359 // Function: TextureAttrib::output 00360 // Access: Public, Virtual 00361 // Description: 00362 //////////////////////////////////////////////////////////////////// 00363 void TextureAttrib:: 00364 output(ostream &out) const { 00365 check_sorted(); 00366 00367 out << get_type() << ":"; 00368 if (_off_stages.empty()) { 00369 if (_on_stages.empty()) { 00370 if (_off_all_stages) { 00371 out << "all off"; 00372 } else { 00373 out << "identity"; 00374 } 00375 } else { 00376 if (_off_all_stages) { 00377 out << "set"; 00378 } else { 00379 out << "on"; 00380 } 00381 } 00382 00383 } else { 00384 out << "off"; 00385 Stages::const_iterator fi; 00386 for (fi = _off_stages.begin(); fi != _off_stages.end(); ++fi) { 00387 TextureStage *stage = (*fi)._stage; 00388 out << " " << stage->get_name(); 00389 if ((*fi)._override != 0) { 00390 out << "^" << (*fi)._override; 00391 } 00392 } 00393 00394 if (!_on_stages.empty()) { 00395 out << " on"; 00396 } 00397 } 00398 00399 RenderStages::const_iterator ri; 00400 for (ri = _render_stages.begin(); ri != _render_stages.end(); ++ri) { 00401 const StageNode &sn = *(*ri); 00402 TextureStage *stage = sn._stage; 00403 Texture *tex = sn._texture; 00404 if (tex != NULL) { 00405 out << " " << stage->get_name() << ":" << tex->get_name(); 00406 } else { 00407 out << " " << stage->get_name(); 00408 } 00409 if (sn._override != 0) { 00410 out << "^" << sn._override; 00411 } 00412 } 00413 } 00414 00415 //////////////////////////////////////////////////////////////////// 00416 // Function: TextureAttrib::has_cull_callback 00417 // Access: Public, Virtual 00418 // Description: Should be overridden by derived classes to return 00419 // true if cull_callback() has been defined. Otherwise, 00420 // returns false to indicate cull_callback() does not 00421 // need to be called for this node during the cull 00422 // traversal. 00423 //////////////////////////////////////////////////////////////////// 00424 bool TextureAttrib:: 00425 has_cull_callback() const { 00426 Stages::const_iterator si; 00427 for (si = _on_stages.begin(); si != _on_stages.end(); ++si) { 00428 Texture *texture = (*si)._texture; 00429 if (texture->has_cull_callback()) { 00430 return true; 00431 } 00432 } 00433 00434 return false; 00435 } 00436 00437 //////////////////////////////////////////////////////////////////// 00438 // Function: TextureAttrib::cull_callback 00439 // Access: Public, Virtual 00440 // Description: If has_cull_callback() returns true, this function 00441 // will be called during the cull traversal to perform 00442 // any additional operations that should be performed at 00443 // cull time. 00444 // 00445 // This is called each time the RenderAttrib is 00446 // discovered applied to a Geom in the traversal. It 00447 // should return true if the Geom is visible, false if 00448 // it should be omitted. 00449 //////////////////////////////////////////////////////////////////// 00450 bool TextureAttrib:: 00451 cull_callback(CullTraverser *trav, const CullTraverserData &data) const { 00452 Stages::const_iterator si; 00453 for (si = _on_stages.begin(); si != _on_stages.end(); ++si) { 00454 Texture *texture = (*si)._texture; 00455 if (!texture->cull_callback(trav, data)) { 00456 return false; 00457 } 00458 } 00459 00460 return true; 00461 } 00462 00463 //////////////////////////////////////////////////////////////////// 00464 // Function: TextureAttrib::compare_to_impl 00465 // Access: Protected, Virtual 00466 // Description: Intended to be overridden by derived TextureAttrib 00467 // types to return a unique number indicating whether 00468 // this TextureAttrib is equivalent to the other one. 00469 // 00470 // This should return 0 if the two TextureAttrib objects 00471 // are equivalent, a number less than zero if this one 00472 // should be sorted before the other one, and a number 00473 // greater than zero otherwise. 00474 // 00475 // This will only be called with two TextureAttrib 00476 // objects whose get_type() functions return the same. 00477 //////////////////////////////////////////////////////////////////// 00478 int TextureAttrib:: 00479 compare_to_impl(const RenderAttrib *other) const { 00480 const TextureAttrib *ta; 00481 DCAST_INTO_R(ta, other, 0); 00482 00483 if (_off_all_stages != ta->_off_all_stages) { 00484 return (int)_off_all_stages - (int)ta->_off_all_stages; 00485 } 00486 00487 Stages::const_iterator si = _on_stages.begin(); 00488 Stages::const_iterator osi = ta->_on_stages.begin(); 00489 00490 while (si != _on_stages.end() && osi != ta->_on_stages.end()) { 00491 TextureStage *stage = (*si)._stage; 00492 TextureStage *other_stage = (*osi)._stage; 00493 00494 if (stage != other_stage) { 00495 return stage < other_stage ? -1 : 1; 00496 } 00497 00498 Texture *texture = (*si)._texture; 00499 Texture *other_texture = (*osi)._texture; 00500 00501 if (texture != other_texture) { 00502 return texture < other_texture ? -1 : 1; 00503 } 00504 00505 int implicit_sort = (*si)._implicit_sort; 00506 int other_implicit_sort = (*osi)._implicit_sort; 00507 00508 if (implicit_sort != other_implicit_sort) { 00509 return implicit_sort < other_implicit_sort ? -1 : 1; 00510 } 00511 00512 int override = (*si)._override; 00513 int other_override = (*osi)._override; 00514 00515 if (override != other_override) { 00516 return override < other_override ? -1 : 1; 00517 } 00518 00519 ++si; 00520 ++osi; 00521 } 00522 00523 if (si != _on_stages.end()) { 00524 return 1; 00525 } 00526 if (osi != ta->_on_stages.end()) { 00527 return -1; 00528 } 00529 00530 // Finally, ensure that the set of off stages is the same. 00531 Stages::const_iterator fi = _off_stages.begin(); 00532 Stages::const_iterator ofi = ta->_off_stages.begin(); 00533 00534 while (fi != _off_stages.end() && ofi != ta->_off_stages.end()) { 00535 TextureStage *stage = (*fi)._stage; 00536 TextureStage *other_stage = (*ofi)._stage; 00537 00538 if (stage != other_stage) { 00539 return stage < other_stage ? -1 : 1; 00540 } 00541 00542 int override = (*fi)._override; 00543 int other_override = (*ofi)._override; 00544 00545 if (override != other_override) { 00546 return override < other_override ? -1 : 1; 00547 } 00548 00549 ++fi; 00550 ++ofi; 00551 } 00552 00553 if (fi != _off_stages.end()) { 00554 return 1; 00555 } 00556 if (ofi != ta->_off_stages.end()) { 00557 return -1; 00558 } 00559 00560 return 0; 00561 } 00562 00563 //////////////////////////////////////////////////////////////////// 00564 // Function: TextureAttrib::compose_impl 00565 // Access: Protected, Virtual 00566 // Description: Intended to be overridden by derived RenderAttrib 00567 // types to specify how two consecutive RenderAttrib 00568 // objects of the same type interact. 00569 // 00570 // This should return the result of applying the other 00571 // RenderAttrib to a node in the scene graph below this 00572 // RenderAttrib, which was already applied. In most 00573 // cases, the result is the same as the other 00574 // RenderAttrib (that is, a subsequent RenderAttrib 00575 // completely replaces the preceding one). On the other 00576 // hand, some kinds of RenderAttrib (for instance, 00577 // ColorTransformAttrib) might combine in meaningful 00578 // ways. 00579 //////////////////////////////////////////////////////////////////// 00580 CPT(RenderAttrib) TextureAttrib:: 00581 compose_impl(const RenderAttrib *other) const { 00582 const TextureAttrib *ta; 00583 DCAST_INTO_R(ta, other, 0); 00584 00585 if (ta->_off_all_stages) { 00586 // If the other type turns off all stages, it doesn't matter what 00587 // we are. 00588 return ta; 00589 } 00590 00591 // This is a three-way merge between ai, bi, and ci, except that bi 00592 // and ci should have no intersection and therefore needn't be 00593 // compared to each other. 00594 Stages::const_iterator ai = _on_stages.begin(); 00595 Stages::const_iterator bi = ta->_on_stages.begin(); 00596 Stages::const_iterator ci = ta->_off_stages.begin(); 00597 00598 // Create a new TextureAttrib that will hold the result. 00599 TextureAttrib *attrib = new TextureAttrib; 00600 00601 while (ai != _on_stages.end() && 00602 bi != ta->_on_stages.end() && 00603 ci != ta->_off_stages.end()) { 00604 if ((*ai)._stage < (*bi)._stage) { 00605 if ((*ai)._stage < (*ci)._stage) { 00606 // Here is a stage that we have in the original, which is not 00607 // present in the secondary. 00608 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); 00609 ++ai; 00610 00611 } else if ((*ci)._stage < (*ai)._stage) { 00612 // Here is a stage that is turned off in the secondary, but 00613 // was not present in the original. 00614 ++ci; 00615 00616 } else { // (*ci)._stage == (*ai)._stage 00617 // Here is a stage that is turned off in the secondary, and 00618 // was present in the original. 00619 if ((*ai)._override > (*ci)._override) { 00620 // But never mind, keep it anyway. 00621 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); 00622 } 00623 00624 ++ai; 00625 ++ci; 00626 } 00627 00628 } else if ((*bi)._stage < (*ai)._stage) { 00629 // Here is a new stage we have in the secondary, that was not 00630 // present in the original. 00631 attrib->_on_stages.insert(attrib->_on_stages.end(), *bi); 00632 ++bi; 00633 00634 } else { // (*bi)._stage == (*ai)._stage 00635 // Here is a stage we have in both. 00636 if ((*ai)._override > (*bi)._override) { 00637 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); 00638 } else { 00639 attrib->_on_stages.insert(attrib->_on_stages.end(), *bi); 00640 } 00641 ++ai; 00642 ++bi; 00643 } 00644 } 00645 00646 while (ai != _on_stages.end() && bi != ta->_on_stages.end()) { 00647 if ((*ai)._stage < (*bi)._stage) { 00648 // Here is a stage that we have in the original, which is not 00649 // present in the secondary. 00650 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); 00651 ++ai; 00652 00653 } else if ((*bi)._stage < (*ai)._stage) { 00654 // Here is a new stage we have in the secondary, that was not 00655 // present in the original. 00656 attrib->_on_stages.insert(attrib->_on_stages.end(), *bi); 00657 ++bi; 00658 00659 } else { 00660 // Here is a stage we have in both. 00661 if ((*ai)._override > (*bi)._override) { 00662 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); 00663 } else { 00664 attrib->_on_stages.insert(attrib->_on_stages.end(), *bi); 00665 } 00666 ++ai; 00667 ++bi; 00668 } 00669 } 00670 00671 while (ai != _on_stages.end() && ci != ta->_off_stages.end()) { 00672 if ((*ai)._stage < (*ci)._stage) { 00673 // Here is a stage that we have in the original, which is not 00674 // present in the secondary. 00675 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); 00676 ++ai; 00677 00678 } else if ((*ci)._stage < (*ai)._stage) { 00679 // Here is a stage that is turned off in the secondary, but 00680 // was not present in the original. 00681 ++ci; 00682 00683 } else { // (*ci)._stage == (*ai)._stage 00684 // Here is a stage that is turned off in the secondary, and 00685 // was present in the original. 00686 if ((*ai)._override > (*ci)._override) { 00687 // But never mind, keep it anyway. 00688 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); 00689 } 00690 ++ai; 00691 ++ci; 00692 } 00693 } 00694 00695 while (ai != _on_stages.end()) { 00696 attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); 00697 ++ai; 00698 } 00699 00700 while (bi != ta->_on_stages.end()) { 00701 attrib->_on_stages.insert(attrib->_on_stages.end(), *bi); 00702 ++bi; 00703 } 00704 00705 attrib->_next_implicit_sort = _next_implicit_sort + ta->_next_implicit_sort; 00706 attrib->_sort_seq = UpdateSeq::old(); 00707 attrib->_filtered_seq = UpdateSeq::old(); 00708 00709 return return_new(attrib); 00710 } 00711 00712 //////////////////////////////////////////////////////////////////// 00713 // Function: TextureAttrib::invert_compose_impl 00714 // Access: Protected, Virtual 00715 // Description: Intended to be overridden by derived RenderAttrib 00716 // types to specify how two consecutive RenderAttrib 00717 // objects of the same type interact. 00718 // 00719 // See invert_compose() and compose_impl(). 00720 //////////////////////////////////////////////////////////////////// 00721 CPT(RenderAttrib) TextureAttrib:: 00722 invert_compose_impl(const RenderAttrib *other) const { 00723 // I think in this case the other attrib always wins. Maybe this 00724 // needs a bit more thought. It's hard to imagine that it's even 00725 // important to compute this properly. 00726 return other; 00727 } 00728 00729 //////////////////////////////////////////////////////////////////// 00730 // Function: TextureAttrib::register_with_read_factory 00731 // Access: Public, Static 00732 // Description: Tells the BamReader how to create objects of type 00733 // TextureAttrib. 00734 //////////////////////////////////////////////////////////////////// 00735 void TextureAttrib:: 00736 register_with_read_factory() { 00737 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 00738 } 00739 00740 //////////////////////////////////////////////////////////////////// 00741 // Function: TextureAttrib::write_datagram 00742 // Access: Public, Virtual 00743 // Description: Writes the contents of this object to the datagram 00744 // for shipping out to a Bam file. 00745 //////////////////////////////////////////////////////////////////// 00746 void TextureAttrib:: 00747 write_datagram(BamWriter *manager, Datagram &dg) { 00748 RenderAttrib::write_datagram(manager, dg); 00749 00750 // Write the off_stages information 00751 dg.add_bool(_off_all_stages); 00752 dg.add_uint16(get_num_off_stages()); 00753 Stages::const_iterator fi; 00754 for (fi = _off_stages.begin(); fi != _off_stages.end(); ++fi) { 00755 TextureStage *stage = (*fi)._stage; 00756 manager->write_pointer(dg, stage); 00757 } 00758 00759 // Write the on_stages information 00760 dg.add_uint16(get_num_on_stages()); 00761 Stages::const_iterator si; 00762 for (si = _on_stages.begin(); si != _on_stages.end(); ++si) { 00763 TextureStage *stage = (*si)._stage; 00764 Texture *tex = (*si)._texture; 00765 nassertv(tex != (Texture *)NULL); 00766 00767 manager->write_pointer(dg, stage); 00768 manager->write_pointer(dg, tex); 00769 dg.add_uint16((*si)._implicit_sort); 00770 dg.add_int32((*si)._override); 00771 } 00772 } 00773 00774 //////////////////////////////////////////////////////////////////// 00775 // Function: TextureAttrib::complete_pointers 00776 // Access: Public, Virtual 00777 // Description: Receives an array of pointers, one for each time 00778 // manager->read_pointer() was called in fillin(). 00779 // Returns the number of pointers processed. 00780 //////////////////////////////////////////////////////////////////// 00781 int TextureAttrib:: 00782 complete_pointers(TypedWritable **p_list, BamReader *manager) { 00783 int pi = RenderAttrib::complete_pointers(p_list, manager); 00784 00785 Stages::iterator ci; 00786 for (ci = _off_stages.begin(); ci != _off_stages.end(); ++ci) { 00787 TextureStage *ts = DCAST(TextureStage, p_list[pi++]); 00788 *ci = StageNode(ts); 00789 } 00790 00791 size_t sni = 0; 00792 while (sni < _on_stages.size()) { 00793 // Filter the TextureStage through the TextureStagePool. 00794 PT(TextureStage) ts = DCAST(TextureStage, p_list[pi++]); 00795 ts = TextureStagePool::get_stage(ts); 00796 00797 // The Texture pointer filters itself through the TexturePool, so 00798 // we don't have to do anything special here. 00799 Texture *tex = DCAST(Texture, p_list[pi++]); 00800 00801 if (tex != (Texture *)NULL) { 00802 StageNode &sn = _on_stages[sni]; 00803 sn._stage = ts; 00804 sn._texture = tex; 00805 ++sni; 00806 00807 } else { 00808 // If we couldn't load a texture pointer, turn off that 00809 // particular texture stage. 00810 _off_stages.push_back(StageNode(ts)); 00811 _on_stages.erase(_on_stages.begin() + sni); 00812 } 00813 } 00814 _on_stages.sort(); 00815 _sort_seq = UpdateSeq::old(); 00816 _filtered_seq = UpdateSeq::old(); 00817 00818 return pi; 00819 } 00820 00821 //////////////////////////////////////////////////////////////////// 00822 // Function: TextureAttrib::make_from_bam 00823 // Access: Protected, Static 00824 // Description: This function is called by the BamReader's factory 00825 // when a new object of type TextureAttrib is encountered 00826 // in the Bam file. It should create the TextureAttrib 00827 // and extract its information from the file. 00828 //////////////////////////////////////////////////////////////////// 00829 TypedWritable *TextureAttrib:: 00830 make_from_bam(const FactoryParams ¶ms) { 00831 TextureAttrib *attrib = new TextureAttrib; 00832 DatagramIterator scan; 00833 BamReader *manager; 00834 00835 parse_params(params, scan, manager); 00836 attrib->fillin(scan, manager); 00837 00838 return attrib; 00839 } 00840 00841 //////////////////////////////////////////////////////////////////// 00842 // Function: TextureAttrib::fillin 00843 // Access: Protected 00844 // Description: This internal function is called by make_from_bam to 00845 // read in all of the relevant data from the BamFile for 00846 // the new TextureAttrib. 00847 //////////////////////////////////////////////////////////////////// 00848 void TextureAttrib:: 00849 fillin(DatagramIterator &scan, BamReader *manager) { 00850 RenderAttrib::fillin(scan, manager); 00851 00852 // read the _off_stages data. 00853 _off_all_stages = scan.get_bool(); 00854 int num_off_stages = scan.get_uint16(); 00855 00856 // Push back a NULL pointer for each off TextureStage for now, until 00857 // we get the actual list of pointers later in complete_pointers(). 00858 int i; 00859 _off_stages.reserve(num_off_stages); 00860 for (i = 0; i < num_off_stages; i++) { 00861 manager->read_pointer(scan); 00862 _off_stages.push_back(StageNode(NULL)); 00863 } 00864 00865 // Read the _on_stages data. 00866 int num_on_stages = scan.get_uint16(); 00867 00868 // Push back a NULL pointer for each off TextureStage and Texture 00869 // for now, until we get the actual list of pointers later in 00870 // complete_pointers(). 00871 _on_stages.reserve(num_on_stages); 00872 _next_implicit_sort = 0; 00873 for (i = 0; i < num_on_stages; i++) { 00874 manager->read_pointer(scan); 00875 manager->read_pointer(scan); 00876 unsigned int implicit_sort; 00877 if (manager->get_file_minor_ver() >= 15) { 00878 implicit_sort = scan.get_uint16(); 00879 } else { 00880 implicit_sort = (unsigned int)i; 00881 } 00882 int override = 0; 00883 if (manager->get_file_minor_ver() >= 23) { 00884 override = scan.get_int32(); 00885 } 00886 00887 _next_implicit_sort = max(_next_implicit_sort, implicit_sort + 1); 00888 _on_stages.push_back(StageNode(NULL, _next_implicit_sort, override)); 00889 ++_next_implicit_sort; 00890 } 00891 } 00892 00893 //////////////////////////////////////////////////////////////////// 00894 // Function: TextureAttrib::sort_on_stages 00895 // Access: Private 00896 // Description: Sorts the list of stages so that they are listed in 00897 // render order. Also clears the _filtered map and 00898 // recalculates the list of fixed-function stages. 00899 //////////////////////////////////////////////////////////////////// 00900 void TextureAttrib:: 00901 sort_on_stages() { 00902 typedef pmap<const InternalName *, int> UsedTexcoordIndex; 00903 UsedTexcoordIndex used_texcoord_index; 00904 00905 _render_stages.clear(); 00906 _render_ff_stages.clear(); 00907 00908 Stages::iterator si; 00909 for (si = _on_stages.begin(); si != _on_stages.end(); ++si) { 00910 StageNode &sn = (*si); 00911 TextureStage *stage = sn._stage; 00912 nassertv(stage != NULL); 00913 if (stage->is_fixed_function()) { 00914 const InternalName *name = stage->get_texcoord_name(); 00915 00916 // This pair of lines will get the next consecutive texcoord index 00917 // number if this is the first time we have referenced this 00918 // particular texcoord name; otherwise, it will return the same 00919 // index number it returned before. 00920 UsedTexcoordIndex::iterator ti = used_texcoord_index.insert(UsedTexcoordIndex::value_type(name, (int)used_texcoord_index.size())).first; 00921 (*si)._ff_tc_index = (*ti).second; 00922 00923 _render_ff_stages.push_back(&sn); 00924 } else { 00925 (*si)._ff_tc_index = -1; 00926 } 00927 00928 _render_stages.push_back(&sn); 00929 } 00930 00931 sort(_render_stages.begin(), _render_stages.end(), CompareTextureStageSort()); 00932 sort(_render_ff_stages.begin(), _render_ff_stages.end(), CompareTextureStageSort()); 00933 00934 // We'd like to clear the _filtered map, in case the TextureStage 00935 // priority values have changed as well, but we can't do that here: 00936 // it's too dangerous. Clearing _filtered might cause 00937 // TextureAttribs to be deleted, and hence removed from the map that 00938 // we might be in the middle of traversing! 00939 00940 _sort_seq = TextureStage::get_sort_seq(); 00941 }