Browse Source

TextureAttrib::_implicit_sort

David Rose 17 years ago
parent
commit
a667e91dce

+ 7 - 11
panda/src/dxgsg9/dxShaderContext9.cxx

@@ -487,17 +487,13 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg)
           }        
           InternalName *name = _shader->_var_spec[i]._name;
           int texslot = _shader->_var_spec[i]._append_uv;
-          if (texslot >= 0) {
-            const Geom::ActiveTextureStages &active_stages =
-              gsg->_state._texture->get_on_stages();
-            if (texslot < (int)active_stages.size()) {
-              TextureStage *stage = active_stages[texslot];
-              InternalName *texname = stage->get_texcoord_name();
-              if (name == InternalName::get_texcoord()) {
-                name = texname;
-              } else if (texname != InternalName::get_texcoord()) {
-                name = name->append(texname->get_basename());
-              }
+          if (texslot >= 0 && texslot < gsg->_state._texture->get_num_on_stages()) {
+            TextureStage *stage = gsg->_state._texture->get_on_stage(texslot);
+            InternalName *texname = stage->get_texcoord_name();
+            if (name == InternalName::get_texcoord()) {
+              name = texname;
+            } else if (texname != InternalName::get_texcoord()) {
+              name = name->append(texname->get_basename());
             }
           }
           if (gsg->_data_reader->get_array_info(name, array_reader, num_values, numeric_type, start, stride)) {

+ 6 - 16
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1988,16 +1988,11 @@ update_standard_vertex_arrays(bool force) {
     // Now set up each of the active texture coordinate stages--or at
     // least those for which we're not generating texture coordinates
     // automatically.
-    const Geom::ActiveTextureStages &active_stages =
-      _effective_texture->get_on_ff_stages();
-    const Geom::NoTexCoordStages &no_texcoords =
-      _effective_tex_gen->get_no_texcoords();
-
-    int max_stage_index = (int)active_stages.size();
+    int max_stage_index = _effective_texture->get_num_on_ff_stages();
     int stage_index = 0;
     while (stage_index < max_stage_index) {
-      TextureStage *stage = active_stages[stage_index];
-      if (no_texcoords.find(stage) == no_texcoords.end()) {
+      TextureStage *stage = _effective_texture->get_on_ff_stage(stage_index);
+      if (!_effective_tex_gen->has_gen_texcoord_stage(stage)) {
         // This stage is not one of the stages that doesn't need
         // texcoords issued for it.
         const InternalName *name = stage->get_texcoord_name();
@@ -2089,17 +2084,12 @@ update_standard_vertex_arrays(bool force) {
     // Now set up each of the active texture coordinate stages--or at
     // least those for which we're not generating texture coordinates
     // automatically.
-    const Geom::ActiveTextureStages &active_stages =
-      _effective_texture->get_on_ff_stages();
-    const Geom::NoTexCoordStages &no_texcoords =
-      _effective_tex_gen->get_no_texcoords();
-    
-    int max_stage_index = (int)active_stages.size();
+    int max_stage_index = _effective_texture->get_num_on_ff_stages();
     int stage_index = 0;
     while (stage_index < max_stage_index) {
       _glClientActiveTexture(GL_TEXTURE0 + stage_index);
-      TextureStage *stage = active_stages[stage_index];
-      if (no_texcoords.find(stage) == no_texcoords.end()) {
+      TextureStage *stage = _effective_texture->get_on_ff_stage(stage_index);
+      if (!_effective_tex_gen->has_gen_texcoord_stage(stage)) {
         // This stage is not one of the stages that doesn't need
         // texcoords issued for it.
         const InternalName *name = stage->get_texcoord_name();

+ 7 - 11
panda/src/glstuff/glShaderContext_src.cxx

@@ -260,17 +260,13 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg,
       if (p == 0) continue;
       InternalName *name = _shader->_var_spec[i]._name;
       int texslot = _shader->_var_spec[i]._append_uv;
-      if (texslot >= 0) {
-        const Geom::ActiveTextureStages &active_stages =
-          gsg->_state._texture->get_on_stages();
-        if (texslot < (int)active_stages.size()) {
-          TextureStage *stage = active_stages[texslot];
-          InternalName *texname = stage->get_texcoord_name();
-          if (name == InternalName::get_texcoord()) {
-            name = texname;
-          } else if (texname != InternalName::get_texcoord()) {
-            name = name->append(texname->get_basename());
-          }
+      if (texslot >= 0 && texslot < gsg->_state._texture->get_num_on_stages()) {
+        TextureStage *stage = gsg->_state._texture->get_on_stage(texslot);
+        InternalName *texname = stage->get_texcoord_name();
+        if (name == InternalName::get_texcoord()) {
+          name = texname;
+        } else if (texname != InternalName::get_texcoord()) {
+          name = name->append(texname->get_basename());
         }
       }
       if (gsg->_data_reader->get_array_info(name,

+ 0 - 4
panda/src/gobj/geom.h

@@ -158,10 +158,6 @@ public:
 
   static UpdateSeq get_next_modified();
 
-public:
-  typedef pvector< PT(TextureStage) > ActiveTextureStages;
-  typedef pset<TextureStage *> NoTexCoordStages;
-
 private:
   class CData;
 

+ 4 - 0
panda/src/mesadisplay/mesagsg.h

@@ -26,6 +26,10 @@
 #include "pandabase.h"
 #include "config_mesadisplay.h"
 
+// This stuff seems to crash with Mesa.
+#undef HAVE_CG
+#undef HAVE_CGGL
+
 #ifdef MESA_MGL
   #define GLP(name) mgl##name
   #define GLUP(name) mglu##name

+ 0 - 14
panda/src/pgraph/texGenAttrib.I

@@ -66,20 +66,6 @@ get_geom_rendering(int geom_rendering) const {
   return geom_rendering | _geom_rendering;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: TexGenAttrib::get_no_texcoords
-//       Access: Public
-//  Description: Returns the set of TextureStages that have texture
-//               coordinates computed for them, and hence do not need
-//               to have texture coordinates sent from the Geom.  This
-//               is, of course, the set of TextureStages that is
-//               listed in the attrib (except for those listed with M_off).
-////////////////////////////////////////////////////////////////////
-INLINE const Geom::NoTexCoordStages &TexGenAttrib::
-get_no_texcoords() const {
-  return _no_texcoords;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: TexGenAttrib::get_light_vectors
 //       Access: Public

+ 14 - 0
panda/src/pgraph/texGenAttrib.cxx

@@ -216,6 +216,20 @@ get_mode(TextureStage *stage) const {
   return M_off;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TexGenAttrib::has_gen_texcoord_stage
+//       Access: Published
+//  Description: Returns true if the indicated TextureStage will have
+//               texture coordinates generated for it automatically
+//               (and thus there is no need to upload the texture
+//               coordinates encoded in the vertices).
+////////////////////////////////////////////////////////////////////
+bool TexGenAttrib::
+has_gen_texcoord_stage(TextureStage *stage) const {
+  NoTexCoordStages::const_iterator mi = _no_texcoords.find(stage);
+  return (mi != _no_texcoords.end());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TexGenAttrib::get_source_name
 //       Access: Published

+ 3 - 3
panda/src/pgraph/texGenAttrib.h

@@ -64,6 +64,7 @@ PUBLISHED:
   bool is_empty() const;
   bool has_stage(TextureStage *stage) const;
   Mode get_mode(TextureStage *stage) const;
+  bool has_gen_texcoord_stage(TextureStage *stage) const;
   string get_source_name(TextureStage *stage) const;
   NodePath get_light(TextureStage *stage) const;
   const TexCoord3f &get_constant_value(TextureStage *stage) const;
@@ -71,8 +72,6 @@ PUBLISHED:
   INLINE int get_geom_rendering(int geom_rendering) const;
 
 public:
-  INLINE const Geom::NoTexCoordStages &get_no_texcoords() const;
-
   typedef pset<TextureStage *> LightVectors;
   INLINE const LightVectors &get_light_vectors() const;
 
@@ -106,7 +105,8 @@ private:
   // coordinates will not be needed from the Geom.  It's redundant;
   // it's almost the same set that is listed in _stages, above.  It's
   // just here as an optimization during rendering.
-  Geom::NoTexCoordStages _no_texcoords;
+  typedef pset<TextureStage *> NoTexCoordStages;
+  NoTexCoordStages _no_texcoords;
 
   // This is another optimization during rendering; it lists the
   // texture stages (if any) that use M_light_vector.

+ 32 - 28
panda/src/pgraph/textureAttrib.I

@@ -25,6 +25,7 @@
 ////////////////////////////////////////////////////////////////////
 INLINE TextureAttrib::
 TextureAttrib() {
+  _next_implicit_sort = 0;
   _off_all_stages = false;
   _sort_seq = UpdateSeq::old();
 }
@@ -39,6 +40,9 @@ TextureAttrib() {
 INLINE TextureAttrib::
 TextureAttrib(const TextureAttrib &copy) :
   _on_stages(copy._on_stages),
+  _on_ff_stages(copy._on_ff_stages),
+  _ff_tc_index(copy._ff_tc_index),
+  _next_implicit_sort(copy._next_implicit_sort),
   _off_stages(copy._off_stages),
   _off_all_stages(copy._off_all_stages),
   _on_textures(copy._on_textures),
@@ -101,7 +105,7 @@ get_num_on_stages() const {
 INLINE TextureStage *TextureAttrib::
 get_on_stage(int n) const {
   nassertr(n >= 0 && n < (int)_on_stages.size(), (TextureStage *)NULL);
-  return _on_stages[n];
+  return _on_stages[n]._stage;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -128,7 +132,7 @@ get_num_on_ff_stages() const {
 INLINE TextureStage *TextureAttrib::
 get_on_ff_stage(int n) const {
   nassertr(n >= 0 && n < (int)_on_ff_stages.size(), (TextureStage *)NULL);
-  return _on_ff_stages[n];
+  return _on_ff_stages[n]._stage;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -231,32 +235,6 @@ is_identity() const {
   return _on_stages.empty() && _off_stages.empty() && !_off_all_stages;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: TextureAttrib::get_on_stages
-//       Access: Public
-//  Description: Returns the complete list of stages defined within
-//               this TextureAttrib, suitable for passing to
-//               Geom::setup_multitexcoord_iterator().
-////////////////////////////////////////////////////////////////////
-INLINE const Geom::ActiveTextureStages &TextureAttrib::
-get_on_stages() const {
-  return _on_stages;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TextureAttrib::get_on_ff_stages
-//       Access: Public
-//  Description: Returns the complete list of stages defined within
-//               this TextureAttrib, including only those which are
-//               relevant to the classic fixed-function pipeline.
-//               The result is suitable for passing to
-//               Geom::setup_multitexcoord_iterator().
-////////////////////////////////////////////////////////////////////
-INLINE const Geom::ActiveTextureStages &TextureAttrib::
-get_on_ff_stages() const {
-  return _on_ff_stages;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureAttrib::check_sorted
 //       Access: Private
@@ -273,3 +251,29 @@ check_sorted() const {
     ((TextureAttrib *)this)->sort_on_stages();
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureAttrib::OnStageNode::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE TextureAttrib::OnStageNode::
+OnStageNode(TextureStage *stage, unsigned int implicit_sort) :
+  _stage(stage),
+  _implicit_sort(implicit_sort)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureAttrib::OnStageNode::Comparison Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE bool TextureAttrib::OnStageNode::
+operator < (const TextureAttrib::OnStageNode &other) const {
+  if (_stage->get_sort() != other._stage->get_sort()) {
+    return _stage->get_sort() < other._stage->get_sort();
+  }
+  return _implicit_sort < other._implicit_sort;
+}
+

+ 209 - 103
panda/src/pgraph/textureAttrib.cxx

@@ -33,16 +33,17 @@ TypeHandle TextureAttrib::_type_handle;
 // This STL Function object is used in filter_to_max(), below, to sort
 // a list of TextureStages in reverse order by priority and, within
 // priority, in order by sort.
-class CompareTextureStagePriorities {
-public:
-  bool operator ()(const TextureStage *a, const TextureStage *b) const {
-    if (a->get_priority() != b->get_priority()) {
-      return a->get_priority() > b->get_priority();
-    }
-    return a->get_sort() < b->get_sort();
+bool TextureAttrib::CompareTextureStagePriorities::
+operator () (const TextureAttrib::OnStageNode &a, 
+             const TextureAttrib::OnStageNode &b) const {
+  if (a._stage->get_priority() != b._stage->get_priority()) {
+    return a._stage->get_priority() > b._stage->get_priority();
   }
-};
-
+  if (a._stage->get_sort() != b._stage->get_sort()) {
+    return a._stage->get_sort() > b._stage->get_sort();
+  }
+  return a._implicit_sort < b._implicit_sort;
+}
 
 
 ////////////////////////////////////////////////////////////////////
@@ -115,7 +116,7 @@ make_all_off() {
 int TextureAttrib::
 find_on_stage(const TextureStage *stage) const {
   for (int n = 0; n < (int)_on_stages.size(); ++n) {
-    if (_on_stages[n] == stage) {
+    if (_on_stages[n]._stage == stage) {
       return n;
     }
   }
@@ -139,7 +140,8 @@ add_on_stage(TextureStage *stage, Texture *tex) const {
     // If the insert was successful--we have added a new stage that
     // wasn't present before--then add the stage to the linear list
     // also.
-    attrib->_on_stages.push_back(stage);
+    attrib->_on_stages.push_back(OnStageNode(stage, attrib->_next_implicit_sort));
+    ++(attrib->_next_implicit_sort);
 
     // Also ensure it is removed from the off_stages list.
     attrib->_off_stages.erase(stage);
@@ -148,6 +150,16 @@ add_on_stage(TextureStage *stage, Texture *tex) const {
     // If the insert was unsuccessful, it means there was already a
     // definition for that stage.  Replace it.
     (*insert_result.first).second = tex;
+
+    // Also update the implicit sort.
+    OnStages::iterator si;
+    for (si = attrib->_on_stages.begin(); si != attrib->_on_stages.end(); ++si) {
+      if ((*si)._stage == stage) {
+        (*si)._implicit_sort = attrib->_next_implicit_sort;
+        ++(attrib->_next_implicit_sort);
+        break;
+      }
+    }
   }
 
   // In either case, we now need to re-sort the attrib list.
@@ -170,13 +182,16 @@ remove_on_stage(TextureStage *stage) const {
   OnTextures::iterator ti = attrib->_on_textures.find(stage);
   if (ti != attrib->_on_textures.end()) {
     attrib->_on_textures.erase(ti);
-    OnStages::iterator si = 
-      find(attrib->_on_stages.begin(), attrib->_on_stages.end(), 
-           PT(TextureStage)(stage));
-    if (si != attrib->_on_stages.end()) {
-      attrib->_on_stages.erase(si);
-      attrib->_sort_seq = UpdateSeq::old();
+    
+    OnStages::iterator si;
+    for (si = attrib->_on_stages.begin(); si != attrib->_on_stages.end(); ++si) {
+      if ((*si)._stage == stage) {
+        attrib->_on_stages.erase(si);
+        break;
+      }
     }
+
+    attrib->_sort_seq = UpdateSeq::old();
   }
 
   return return_new(attrib);
@@ -199,13 +214,15 @@ add_off_stage(TextureStage *stage) const {
     OnTextures::iterator ti = attrib->_on_textures.find(stage);
     if (ti != attrib->_on_textures.end()) {
       attrib->_on_textures.erase(ti);
-      OnStages::iterator si = 
-        find(attrib->_on_stages.begin(), attrib->_on_stages.end(), 
-             PT(TextureStage)(stage));
-      if (si != attrib->_on_stages.end()) {
-        attrib->_on_stages.erase(si);
-        attrib->_sort_seq = UpdateSeq::old();
+    
+      OnStages::iterator si;
+      for (si = attrib->_on_stages.begin(); si != attrib->_on_stages.end(); ++si) {
+        if ((*si)._stage == stage) {
+          attrib->_on_stages.erase(si);
+          break;
+        }
       }
+      attrib->_sort_seq = UpdateSeq::old();
     }
   }
   return return_new(attrib);
@@ -240,25 +257,31 @@ unify_texture_stages(TextureStage *stage) const {
   attrib->_off_all_stages = _off_all_stages;
   bool any_changed = false;
 
-  OnTextures::const_iterator nti;
-  for (nti = _on_textures.begin(); nti != _on_textures.end(); ++nti) {
-    if ((*nti).first != stage && 
-        (*nti).first->get_name() == stage->get_name()) {
-      attrib->_on_textures[stage] = (*nti).second;
+  OnStages::const_iterator si;
+  for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
+    TextureStage *this_stage = (*si)._stage;
+    Texture *tex = get_on_texture(this_stage);
+    nassertr(tex != (Texture *)NULL, this);
+
+    if (this_stage->get_name() == stage->get_name()) {
+      this_stage = stage;
       any_changed = true;
+    }
+
+    bool inserted = attrib->_on_textures.insert(OnTextures::value_type(this_stage, tex)).second;
+    if (inserted) {
+      // If the texture was successfully inserted, it was the first
+      // appearance of this stage.  Add it to the on_stages list.
+      attrib->_on_stages.push_back(OnStageNode(this_stage, (*si)._implicit_sort));
     } else {
-      attrib->_on_textures.insert(*nti);
+      // If the texture was not successfully inserted, it was a
+      // duplicate texture stage.  This should only be possible if we
+      // have just collapsed a stage.
+      nassertr(this_stage == stage, this);
     }
   }
 
-  // Now copy from _on_textures to the _on_stages list.  We can't do
-  // this as we walk through the list the first pass, since we might
-  // have collapsed together multiple different stages.
-  for (nti = attrib->_on_textures.begin(); 
-       nti != attrib->_on_textures.end(); 
-       ++nti) {
-    attrib->_on_stages.push_back((*nti).first);
-  }
+  attrib->_next_implicit_sort = _next_implicit_sort;
 
   OffStages::const_iterator fsi;
   for (fsi = _off_stages.begin(); fsi != _off_stages.end(); ++fsi) {
@@ -323,11 +346,12 @@ filter_to_max(int max_texture_stages) const {
 
   OnStages::const_iterator si;
   for (si = priority_stages.begin(); si != priority_stages.end(); ++si) {
-    TextureStage *stage = (*si);
+    TextureStage *stage = (*si)._stage;
     attrib->_on_textures[stage] = get_on_texture(stage);
   }
 
   attrib->_on_stages.swap(priority_stages);
+  attrib->_next_implicit_sort = _next_implicit_sort;
 
   CPT(RenderAttrib) new_attrib = return_new(attrib);
 
@@ -376,9 +400,9 @@ output(ostream &out) const {
     }
   }
     
-  OnStages::const_iterator li;
-  for (li = _on_stages.begin(); li != _on_stages.end(); ++li) {
-    TextureStage *stage = (*li);
+  OnStages::const_iterator si;
+  for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
+    TextureStage *stage = (*si)._stage;
     OnTextures::const_iterator ti = _on_textures.find(stage);
     if (ti != _on_textures.end()) {
       Texture *tex = (*ti).second;
@@ -461,6 +485,8 @@ compare_to_impl(const RenderAttrib *other) const {
     return (int)_off_all_stages - (int)ta->_off_all_stages;
   }
 
+  // First, verify that the texture assigned to each stage is the
+  // same.
   OnTextures::const_iterator li = _on_textures.begin();
   OnTextures::const_iterator oli = ta->_on_textures.begin();
 
@@ -489,6 +515,43 @@ compare_to_impl(const RenderAttrib *other) const {
     return -1;
   }
 
+  // Then, we also have to check the linear list of texture stages, to
+  // ensure primarily that the implicit sort numbers match between the
+  // two attribs.  (If they did not, then a later call to
+  // texture_stage->set_sort() might make these attribs apply textures
+  // differently, even if they are the same now.)
+  check_sorted();
+  ta->check_sorted();
+
+  OnStages::const_iterator si = _on_stages.begin();
+  OnStages::const_iterator osi = ta->_on_stages.begin();
+
+  while (si != _on_stages.end() && osi != ta->_on_stages.end()) {
+    TextureStage *stage = (*si)._stage;
+    TextureStage *other_stage = (*osi)._stage;
+
+    if (stage != other_stage) {
+      return stage < other_stage ? -1 : 1;
+    }
+
+    int implicit_sort = (*si)._implicit_sort;
+    int other_implicit_sort = (*osi)._implicit_sort;
+    if (implicit_sort != other_implicit_sort) {
+      return implicit_sort < other_implicit_sort ? -1 : 1;
+    }
+
+    ++si;
+    ++osi;
+  }
+
+  if (si != _on_stages.end()) {
+    return 1;
+  }
+  if (osi != ta->_on_stages.end()) {
+    return -1;
+  }
+
+  // Finally, ensure that the set of off stages is the same.
   OffStages::const_iterator fi = _off_stages.begin();
   OffStages::const_iterator ofi = ta->_off_stages.begin();
 
@@ -549,8 +612,14 @@ compose_impl(const RenderAttrib *other) const {
   OnTextures::const_iterator bi = ta->_on_textures.begin();
   OffStages::const_iterator ci = ta->_off_stages.begin();
 
+  // TextureStages that are kept from the original attrib are inserted
+  // into a_stages.  Those that are inherited from the secondary
+  // attrib are inserted into b_stages.
+  pset<TextureStage *> a_stages;
+  pset<TextureStage *> b_stages;
+
   // Create a new TextureAttrib that will hold the result.
-  TextureAttrib *new_attrib = new TextureAttrib;
+  TextureAttrib *attrib = new TextureAttrib;
 
   while (ai != _on_textures.end() && 
          bi != ta->_on_textures.end() && 
@@ -559,8 +628,8 @@ compose_impl(const RenderAttrib *other) const {
       if ((*ai).first < (*ci)) {
         // Here is a stage that we have in the original, which is not
         // present in the secondary.
-        new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *ai);
-        new_attrib->_on_stages.push_back((*ai).first);
+        attrib->_on_textures.insert(attrib->_on_textures.end(), *ai);
+        a_stages.insert((*ai).first);
         ++ai;
 
       } else if ((*ci) < (*ai).first) {
@@ -578,14 +647,14 @@ compose_impl(const RenderAttrib *other) const {
     } else if ((*bi).first < (*ai).first) {
       // Here is a new stage we have in the secondary, that was not
       // present in the original.
-      new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *bi);
-      new_attrib->_on_stages.push_back((*bi).first);
+      attrib->_on_textures.insert(attrib->_on_textures.end(), *bi);
+      b_stages.insert((*bi).first);
       ++bi;
 
     } else {  // (*bi).first == (*ai).first
       // Here is a stage we have in both.
-      new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *bi);
-      new_attrib->_on_stages.push_back((*ai).first);
+      attrib->_on_textures.insert(attrib->_on_textures.end(), *bi);
+      b_stages.insert((*bi).first);
       ++ai;
       ++bi;
     }
@@ -595,21 +664,21 @@ compose_impl(const RenderAttrib *other) const {
     if ((*ai).first < (*bi).first) {
       // Here is a stage that we have in the original, which is not
       // present in the secondary.
-      new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *ai);
-      new_attrib->_on_stages.push_back((*ai).first);
+      attrib->_on_textures.insert(attrib->_on_textures.end(), *ai);
+      a_stages.insert((*ai).first);
       ++ai;
 
     } else if ((*bi).first < (*ai).first) {
       // Here is a new stage we have in the secondary, that was not
       // present in the original.
-      new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *bi);
-      new_attrib->_on_stages.push_back((*bi).first);
+      attrib->_on_textures.insert(attrib->_on_textures.end(), *bi);
+      b_stages.insert((*bi).first);
       ++bi;
 
     } else {
       // Here is a stage we have in both.
-      new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *bi);
-      new_attrib->_on_stages.push_back((*ai).first);
+      attrib->_on_textures.insert(attrib->_on_textures.end(), *bi);
+      b_stages.insert((*bi).first);
       ++ai;
       ++bi;
     }
@@ -619,8 +688,8 @@ compose_impl(const RenderAttrib *other) const {
     if ((*ai).first < (*ci)) {
       // Here is a stage that we have in the original, which is not
       // present in the secondary.
-      new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *ai);
-      new_attrib->_on_stages.push_back((*ai).first);
+      attrib->_on_textures.insert(attrib->_on_textures.end(), *ai);
+      a_stages.insert((*ai).first);
       ++ai;
       
     } else if ((*ci) < (*ai).first) {
@@ -637,18 +706,49 @@ compose_impl(const RenderAttrib *other) const {
   }
 
   while (ai != _on_textures.end()) {
-    new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *ai);
-    new_attrib->_on_stages.push_back((*ai).first);
+    attrib->_on_textures.insert(attrib->_on_textures.end(), *ai);
+    a_stages.insert((*ai).first);
     ++ai;
   }
 
   while (bi != ta->_on_textures.end()) {
-    new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *bi);
-    new_attrib->_on_stages.push_back((*bi).first);
+    attrib->_on_textures.insert(attrib->_on_textures.end(), *bi);
+    b_stages.insert((*bi).first);
     ++bi;
   }
 
-  return return_new(new_attrib);
+  // Now we need to build up the linear list.  We must put this in
+  // order so that the original stages are first, followed by the
+  // secondary stages.  If a texture stage is listed in both, it
+  // receives the secondary sort.
+
+  OnStages::const_iterator asi;
+  for (asi = _on_stages.begin(); asi != _on_stages.end(); ++asi) {
+    TextureStage *stage = (*asi)._stage;
+
+    if (a_stages.find(stage) != a_stages.end()) {
+      // This stage came from the original, and thus receives the
+      // original sort.
+      int implicit_sort = (*asi)._implicit_sort;
+      attrib->_on_stages.push_back(OnStageNode(stage, implicit_sort));
+    }
+  }
+
+  OnStages::const_iterator bsi;
+  for (bsi = ta->_on_stages.begin(); bsi != ta->_on_stages.end(); ++bsi) {
+    TextureStage *stage = (*bsi)._stage;
+
+    if (b_stages.find(stage) != b_stages.end()) {
+      // This stage was inherited from the secondary, and thus
+      // receives the secondary sort.
+      int implicit_sort = _next_implicit_sort + (*bsi)._implicit_sort;
+      attrib->_on_stages.push_back(OnStageNode(stage, implicit_sort));
+    }
+  }
+
+  attrib->_next_implicit_sort = _next_implicit_sort + ta->_next_implicit_sort;
+
+  return return_new(attrib);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -716,31 +816,27 @@ void TextureAttrib::
 write_datagram(BamWriter *manager, Datagram &dg) {
   RenderAttrib::write_datagram(manager, dg);
 
-#if 1
-  // TODO: write the multitexture data.
-  // write the boolean if _off_all_stages
+  // Write the off_stages information
   dg.add_bool(_off_all_stages);
-  // write the number of off_stages
   dg.add_uint16(get_num_off_stages());
-  // write the off stages pointers if any
   OffStages::const_iterator fi;
   for (fi = _off_stages.begin(); fi != _off_stages.end(); ++fi) {
     TextureStage *stage = (*fi);
     manager->write_pointer(dg, stage);
   }
-  // write the number of on stages
+
+  // Write the on_stages information
   dg.add_uint16(get_num_on_stages());
-  // write the on stages pointers if any
-  OnTextures::const_iterator nti;
-  for (nti = _on_textures.begin(); nti != _on_textures.end(); ++nti) {
-    TextureStage *stage = (*nti).first;
+  OnStages::const_iterator si;
+  for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
+    TextureStage *stage = (*si)._stage;
+    Texture *tex = get_on_texture(stage);
+    nassertv(tex != (Texture *)NULL);
+
     manager->write_pointer(dg, stage);
-    Texture *texture = (*nti).second;
-    manager->write_pointer(dg,texture);
+    manager->write_pointer(dg, tex);
+    dg.add_uint16((*si)._implicit_sort);
   }
-#else
-  manager->write_pointer(dg, get_texture());
-#endif
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -754,27 +850,27 @@ int TextureAttrib::
 complete_pointers(TypedWritable **p_list, BamReader *manager) {
   int pi = RenderAttrib::complete_pointers(p_list, manager);
 
-  OffStages::iterator ci = _off_stages.begin();
-  while (ci != _off_stages.end()) {
+  OffStages::iterator ci;
+  for (ci = _off_stages.begin(); ci != _off_stages.end(); ++ci) {
     TextureStage *ts = DCAST(TextureStage, p_list[pi++]);
     *ci = ts;
-    ++ci;
   }
-  
-  // read the pointers of the on_textures
-  _on_stages.reserve(_num_on_textures);
-  
-  for (int i = 0; i < _num_on_textures; ++i) {
+
+  size_t sn = 0;
+  while (sn < _on_stages.size()) {
     TextureStage *ts = DCAST(TextureStage, p_list[pi++]);
-    Texture *tx = DCAST(Texture, p_list[pi++]);
-    if (tx != (Texture *)NULL) {
-      _on_textures[ts] = tx;
-      _on_stages.push_back(ts);
+    Texture *tex = DCAST(Texture, p_list[pi++]);
+    
+    if (tex != (Texture *)NULL) {
+      _on_textures[ts] = tex;
+      _on_stages[sn]._stage = ts;
+      ++sn;
       
     } else {
       // If we couldn't load a texture pointer, turn off that
       // particular texture stage.
       _off_stages.push_back(ts);
+      _on_stages.erase(_on_stages.begin() + sn);
     }
   }
   _sort_seq = UpdateSeq::old();
@@ -813,9 +909,8 @@ void TextureAttrib::
 fillin(DatagramIterator &scan, BamReader *manager) {
   RenderAttrib::fillin(scan, manager);
 
-  // read the boolean if _off_all_stages
+  // read the _off_stages data.
   _off_all_stages = scan.get_bool();
-  // read the number of off_stages
   int num_off_stages = scan.get_uint16();
   
   // Push back a NULL pointer for each off TextureStage for now, until
@@ -826,15 +921,26 @@ fillin(DatagramIterator &scan, BamReader *manager) {
     manager->read_pointer(scan);
     _off_stages.push_back(NULL);
   }
-  // read the number of on stages
-  _num_on_textures = scan.get_uint16();
 
-  // just read the pointers, all allocation will happen from
-  // complete_pointers because it is a map template we get the actual
-  // list of pointers later in complete_pointers().
-  for (i = 0; i < _num_on_textures; i++) {
+  // Read the _on_stages data.
+  int num_on_stages = scan.get_uint16();
+
+  // Push back a NULL pointer for each off TextureStage and Texture
+  // for now, until we get the actual list of pointers later in
+  // complete_pointers().
+  _on_stages.reserve(num_on_stages);
+  _next_implicit_sort = 0;
+  for (i = 0; i < num_on_stages; i++) {
     manager->read_pointer(scan);
     manager->read_pointer(scan);
+    unsigned int implicit_sort;
+    if (manager->get_file_minor_ver() >= 15) {
+      implicit_sort = scan.get_uint16();
+    } else {
+      implicit_sort = (unsigned int)i;
+    }
+    _next_implicit_sort = max(_next_implicit_sort, implicit_sort + 1);
+    _on_stages.push_back(OnStageNode(NULL, implicit_sort));
   }
 }
 
@@ -862,9 +968,9 @@ sort_on_stages() {
   typedef pmap<const TextureStage *, int> TexcoordMap;
   TexcoordMap tc_map;
 
-  OnStages::const_iterator osi;
-  for (osi = _on_stages.begin(); osi != _on_stages.end(); ++osi) {
-    TextureStage *stage = (*osi);
+  OnStages::const_iterator si;
+  for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
+    TextureStage *stage = (*si)._stage;
     if (stage->is_fixed_function()) {
       const InternalName *name = stage->get_texcoord_name();
 
@@ -880,17 +986,17 @@ sort_on_stages() {
   }
 
   // Now we can sort the on_stages map into render order.
-  sort(_on_stages.begin(), _on_stages.end(), IndirectLess<TextureStage>());
+  sort(_on_stages.begin(), _on_stages.end());
 
   _sort_seq = TextureStage::get_sort_seq();
 
   _on_ff_stages.clear();
   _ff_tc_index.clear();
 
-  for (osi = _on_stages.begin(); osi != _on_stages.end(); ++osi) {
-    TextureStage *stage = (*osi);
+  for (si = _on_stages.begin(); si != _on_stages.end(); ++si) {
+    TextureStage *stage = (*si)._stage;
     if (stage->is_fixed_function()) {
-      _on_ff_stages.push_back(stage);
+      _on_ff_stages.push_back(*si);
       int texcoord_index = tc_map[stage];
       _ff_tc_index.push_back(texcoord_index);
     }

+ 19 - 10
panda/src/pgraph/textureAttrib.h

@@ -25,16 +25,14 @@
 #include "texture.h"
 #include "textureStage.h"
 #include "updateSeq.h"
-#include "indirectLess.h"
-#include "geom.h"
 #include "ordered_vector.h"
 #include "vector_int.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : TextureAttrib
-// Description : Indicates which texture should be applied as the
-//               primary texture.  Also see TextureAttrib2 for the
-//               secondary texture.
+// Description : Indicates the set of TextureStages and their
+//               associated Textures that should be applied to (or
+//               removed from) a node.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_PGRAPH TextureAttrib : public RenderAttrib {
 protected:
@@ -81,8 +79,6 @@ PUBLISHED:
   CPT(RenderAttrib) unify_texture_stages(TextureStage *stage) const;
 
 public:
-  INLINE const Geom::ActiveTextureStages &get_on_stages() const;
-  INLINE const Geom::ActiveTextureStages &get_on_ff_stages() const;
   CPT(TextureAttrib) filter_to_max(int max_texture_stages) const;
 
   virtual void output(ostream &out) const;
@@ -102,10 +98,25 @@ private:
   void sort_on_stages();
 
 private:
-  typedef Geom::ActiveTextureStages OnStages;
+  class OnStageNode {
+  public:
+    INLINE OnStageNode(TextureStage *stage, unsigned int implicit_sort);
+    INLINE bool operator < (const OnStageNode &other) const;
+
+    PT(TextureStage) _stage;
+    unsigned int _implicit_sort;
+  };
+
+  class CompareTextureStagePriorities {
+  public:
+    bool operator () (const TextureAttrib::OnStageNode &a, const TextureAttrib::OnStageNode &b) const;
+  };
+
+  typedef pvector<OnStageNode> OnStages;
   OnStages _on_stages;
   OnStages _on_ff_stages;
   vector_int _ff_tc_index;
+  unsigned int _next_implicit_sort;
   
   typedef ov_set<TextureStage *> OffStages;
   OffStages _off_stages;
@@ -119,8 +130,6 @@ private:
 
   UpdateSeq _sort_seq;
 
-  int _num_on_textures;  //temporary count to complete_pointers from fill_in
-
   static CPT(RenderAttrib) _empty_attrib;
   static CPT(RenderAttrib) _all_off_attrib;
 

+ 2 - 1
panda/src/putil/bam.h

@@ -36,7 +36,7 @@ static const unsigned short _bam_major_ver = 6;
 // Bumped to major version 5 on 5/6/05 for new Geom implementation.
 // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
 
-static const unsigned short _bam_minor_ver = 14;
+static const unsigned short _bam_minor_ver = 15;
 // Bumped to minor version 1 on 3/12/06 to add Texture::_compression.
 // Bumped to minor version 2 on 3/17/06 to add PandaNode::_draw_control_mask.
 // Bumped to minor version 3 on 3/21/06 to add Texture::_ram_images.
@@ -51,6 +51,7 @@ static const unsigned short _bam_minor_ver = 14;
 // Bumped to minor version 12 on 7/3/07 to rework control/frozen joints more.
 // Bumped to minor version 13 on 8/15/07 to reverse CollisionPolygon vertices.
 // Bumped to minor version 14 on 12/19/07 to change default ColorAttrib.
+// Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort.
 
 
 #endif