Panda3D

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