Panda3D
 All Classes Functions Variables Enumerations
textureAttrib.cxx
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 &params) {
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 }
 All Classes Functions Variables Enumerations