2
0
Эх сурвалжийг харах

*** empty log message ***

David Rose 25 жил өмнө
parent
commit
872a902de4
41 өөрчлөгдсөн 1188 нэмэгдсэн , 232 устгасан
  1. 4 0
      panda/src/cull/config_cull.cxx
  2. 31 1
      panda/src/cull/cullTraverser.I
  3. 134 16
      panda/src/cull/cullTraverser.cxx
  4. 13 3
      panda/src/cull/cullTraverser.h
  5. 57 22
      panda/src/cull/geomBin.I
  6. 182 41
      panda/src/cull/geomBin.cxx
  7. 26 9
      panda/src/cull/geomBin.h
  8. 6 6
      panda/src/cull/geomBinAttribute.I
  9. 6 6
      panda/src/cull/geomBinAttribute.cxx
  10. 4 4
      panda/src/cull/geomBinAttribute.h
  11. 2 2
      panda/src/cull/geomBinBackToFront.I
  12. 3 4
      panda/src/cull/geomBinBackToFront.h
  13. 2 2
      panda/src/cull/geomBinFixed.I
  14. 3 4
      panda/src/cull/geomBinFixed.h
  15. 2 30
      panda/src/cull/geomBinGroup.I
  16. 148 0
      panda/src/cull/geomBinGroup.cxx
  17. 10 5
      panda/src/cull/geomBinGroup.h
  18. 10 5
      panda/src/cull/geomBinNormal.cxx
  19. 3 3
      panda/src/cull/geomBinNormal.h
  20. 6 6
      panda/src/cull/geomBinTransition.I
  21. 62 6
      panda/src/cull/geomBinTransition.cxx
  22. 16 6
      panda/src/cull/geomBinTransition.h
  23. 2 2
      panda/src/cull/geomBinUnsorted.I
  24. 3 3
      panda/src/cull/geomBinUnsorted.h
  25. 45 15
      panda/src/doc/eggSyntax.txt
  26. 64 8
      panda/src/egg/eggAlphaMode.I
  27. 12 0
      panda/src/egg/eggAlphaMode.cxx
  28. 9 3
      panda/src/egg/eggAlphaMode.h
  29. 51 0
      panda/src/egg/eggGroup.cxx
  30. 4 0
      panda/src/egg/eggGroup.h
  31. 53 0
      panda/src/egg/eggNode.cxx
  32. 5 0
      panda/src/egg/eggNode.h
  33. 60 0
      panda/src/egg/eggPrimitive.cxx
  34. 4 0
      panda/src/egg/eggPrimitive.h
  35. 16 5
      panda/src/egg/parser.yxx
  36. 1 1
      panda/src/egg2sg/Sources.pp
  37. 39 7
      panda/src/egg2sg/eggLoader.cxx
  38. 16 0
      panda/src/express/typeHandle.cxx
  39. 8 7
      panda/src/sgattrib/config_sgattrib.cxx
  40. 57 0
      panda/src/sgattrib/depthWriteTransition.cxx
  41. 9 0
      panda/src/sgattrib/depthWriteTransition.h

+ 4 - 0
panda/src/cull/config_cull.cxx

@@ -31,6 +31,10 @@ ConfigureFn(config_cull) {
   GeomBinAttribute::init_type();
   GeomBinAttribute::init_type();
   GeomBinFixed::init_type();
   GeomBinFixed::init_type();
   DirectRenderTransition::init_type();
   DirectRenderTransition::init_type();
+
+  //Registration of writeable object's creation
+  //functions with BamReader's factory
+  GeomBinTransition::register_with_read_factory();
 }
 }
 
 
 // Set this true to force all of the caching to blow itself away every
 // Set this true to force all of the caching to blow itself away every

+ 31 - 1
panda/src/cull/cullTraverser.I

@@ -20,7 +20,8 @@
 INLINE void CullTraverser::
 INLINE void CullTraverser::
 set_default_bin(GeomBin *bin) {
 set_default_bin(GeomBin *bin) {
   nassertv(bin != (GeomBin *)NULL);
   nassertv(bin != (GeomBin *)NULL);
-  bin->attach_to(this, bin->get_sort());
+  nassertv(bin->is_attached());
+  nassertv(bin->get_traverser() == this);
   _default_bin = bin;
   _default_bin = bin;
 }
 }
 
 
@@ -36,6 +37,35 @@ get_default_bin() const {
   return _default_bin;
   return _default_bin;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::has_bin
+//       Access: Public
+//  Description: Returns true if a bin by the given name has been
+//               attached to the CullTraverser, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool CullTraverser::
+has_bin(const string &name) const {
+  return (_toplevel_bins.count(name) != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::get_bin
+//       Access: Public
+//  Description: Returns the GeomBin that was previously attached to
+//               the CullTraverser that shares the indicated name, or
+//               the default bin if no GeomBin with a matching name
+//               was added.
+////////////////////////////////////////////////////////////////////
+INLINE GeomBin *CullTraverser::
+get_bin(const string &name) const {
+  ToplevelBins::const_iterator tbi;
+  tbi = _toplevel_bins.find(name);
+  if (tbi == _toplevel_bins.end()) {
+    return get_default_bin();
+  }
+  return (*tbi).second;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CullTraverser::draw_geom
 //     Function: CullTraverser::draw_geom
 //       Access: Public
 //       Access: Public

+ 134 - 16
panda/src/cull/cullTraverser.cxx

@@ -8,6 +8,7 @@
 #include "geomBinAttribute.h"
 #include "geomBinAttribute.h"
 #include "cullStateSubtree.h"
 #include "cullStateSubtree.h"
 #include "geomBinNormal.h"
 #include "geomBinNormal.h"
+#include "geomBinFixed.h"
 #include "directRenderTransition.h"
 #include "directRenderTransition.h"
 #include "config_cull.h"
 #include "config_cull.h"
 
 
@@ -42,7 +43,15 @@ CullTraverser(GraphicsStateGuardian *gsg, TypeHandle graph_type,
 	      const ArcChain &arc_chain) :
 	      const ArcChain &arc_chain) :
   RenderTraverser(gsg, graph_type, arc_chain)
   RenderTraverser(gsg, graph_type, arc_chain)
 {
 {
-  _default_bin = new GeomBinNormal("default", this);
+  GeomBinNormal *default_bin = new GeomBinNormal("default");
+  GeomBinFixed *fixed = new GeomBinFixed("fixed");
+  fixed->set_sort(30);
+
+  default_bin->set_traverser(this);
+  fixed->set_traverser(this);
+
+  _default_bin = default_bin;
+
   _nested_count = 0;
   _nested_count = 0;
 }
 }
 
 
@@ -56,12 +65,14 @@ CullTraverser::
   // We should detach each of our associated bins when we destruct.
   // We should detach each of our associated bins when we destruct.
   // We can't just run a for loop, because this is a self-modifying
   // We can't just run a for loop, because this is a self-modifying
   // operation.
   // operation.
-  while (!_bins.empty()) {
-    GeomBin *bin = (*_bins.begin());
+  while (!_toplevel_bins.empty()) {
+    GeomBin *bin = (*_toplevel_bins.begin()).second;
     nassertv(bin != (GeomBin *)NULL);
     nassertv(bin != (GeomBin *)NULL);
     nassertv(bin->get_traverser() == this);
     nassertv(bin->get_traverser() == this);
-    bin->detach();
+    bin->clear_traverser();
   }
   }
+
+  nassertv(_sub_bins.empty());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -86,7 +97,8 @@ traverse(Node *root,
       << *root << "\n";
       << *root << "\n";
   }
   }
 
 
-  nassertv(!_bins.empty());
+  nassertv(!_toplevel_bins.empty());
+  nassertv(!_sub_bins.empty());
 
 
   bool is_initial = (_nested_count == 0);
   bool is_initial = (_nested_count == 0);
   if (is_initial) {
   if (is_initial) {
@@ -184,9 +196,9 @@ write(ostream &out, int indent_level) const {
   }
   }
   */
   */
 
 
-  Bins::const_iterator bi;
-  for (bi = _bins.begin(); bi != _bins.end(); ++bi) {
-    (*bi)->write(out, indent_level);
+  ToplevelBins::const_iterator tbi;
+  for (tbi = _toplevel_bins.begin(); tbi != _toplevel_bins.end(); ++tbi) {
+    (*tbi).second->write(out, indent_level);
   }
   }
   _lookup.write(out, indent_level);
   _lookup.write(out, indent_level);
 }
 }
@@ -215,9 +227,9 @@ draw() {
       << " nonempty states of " << _states.size() << " total.\n";
       << " nonempty states of " << _states.size() << " total.\n";
   }
   }
 
 
-  Bins::iterator bi;
-  for (bi = _bins.begin(); bi != _bins.end(); ++bi) {
-    (*bi)->clear_current_states();
+  SubBins::const_iterator sbi;
+  for (sbi = _sub_bins.begin(); sbi != _sub_bins.end(); ++sbi) {
+    (*sbi).second->clear_current_states();
   }
   }
 
 
   States::iterator si;
   States::iterator si;
@@ -233,7 +245,7 @@ draw() {
       const GeomBinAttribute *bin_attrib;
       const GeomBinAttribute *bin_attrib;
       if (get_attribute_into(bin_attrib, cs->get_attributes(),
       if (get_attribute_into(bin_attrib, cs->get_attributes(),
 			     GeomBinTransition::get_class_type())) {
 			     GeomBinTransition::get_class_type())) {
-	requested_bin = bin_attrib->get_bin();
+	requested_bin = get_bin(bin_attrib->get_bin());
 	draw_order = bin_attrib->get_draw_order();
 	draw_order = bin_attrib->get_draw_order();
       }
       }
 
 
@@ -244,10 +256,10 @@ draw() {
   if (_gsg != (GraphicsStateGuardian *)NULL) {
   if (_gsg != (GraphicsStateGuardian *)NULL) {
     if (cull_cat.is_debug()) {
     if (cull_cat.is_debug()) {
       cull_cat.debug()
       cull_cat.debug()
-	<< "Drawing " << _bins.size() << " bins.\n";
+	<< "Drawing " << _sub_bins.size() << " bins.\n";
     }
     }
-    for (bi = _bins.begin(); bi != _bins.end(); ++bi) {
-      (*bi)->draw(this);
+    for (sbi = _sub_bins.begin(); sbi != _sub_bins.end(); ++sbi) {
+      (*sbi).second->draw(this);
     }
     }
   }
   }
 }
 }
@@ -394,7 +406,6 @@ forward_arc(NodeRelation *arc, NullTransitionWrapper &,
   bool is_geom = node->is_of_type(GeomNode::get_class_type());
   bool is_geom = node->is_of_type(GeomNode::get_class_type());
   bool node_has_sub_render = node->has_sub_render();
   bool node_has_sub_render = node->has_sub_render();
   int arc_num_sub_render = arc->get_num_sub_render_trans();
   int arc_num_sub_render = arc->get_num_sub_render_trans();
-  bool has_direct_render = arc->has_transition(DirectRenderTransition::get_class_type());
   bool has_decal = arc->has_transition(DecalTransition::get_class_type());
   bool has_decal = arc->has_transition(DecalTransition::get_class_type());
 
 
   if (has_decal) {
   if (has_decal) {
@@ -403,6 +414,9 @@ forward_arc(NodeRelation *arc, NullTransitionWrapper &,
     arc_num_sub_render--;
     arc_num_sub_render--;
   }
   }
 
 
+  bool has_direct_render = 
+    arc->has_transition(DirectRenderTransition::get_class_type());
+
 #ifndef NDEBUG
 #ifndef NDEBUG
   if (support_decals != SD_on) {
   if (support_decals != SD_on) {
     has_direct_render = has_direct_render && !has_decal;
     has_direct_render = has_direct_render && !has_decal;
@@ -533,3 +547,107 @@ forward_arc(NodeRelation *arc, NullTransitionWrapper &,
 
 
   return true;
   return true;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::attach_toplevel_bin
+//       Access: Private
+//  Description: This is intended to be called only by
+//               GeomBin::attach().  It stores the bin in the
+//               appropriate structures within the traverser, as a
+//               toplevel bin, e.g. a bin that may be referenced by
+//               name from outside the traverser, or one that geometry
+//               may be explicitly assigned to by name.
+////////////////////////////////////////////////////////////////////
+void CullTraverser::
+attach_toplevel_bin(GeomBin *bin) {
+  if (cull_cat.is_debug()) {
+    cull_cat.debug()
+      << "Attaching toplevel bin " << *bin << "\n";
+  }
+
+  // Insert the new bin by name.
+  bool inserted = 
+    _toplevel_bins.insert(ToplevelBins::value_type(bin->get_name(), bin)).second;
+
+  // If this assertion fails, there was already a bin by the same name
+  // in this traverser, an error condition.
+  nassertv(inserted);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::attach_sub_bin
+//       Access: Private
+//  Description: This is intended to be called only by
+//               GeomBin::attach().  It stores the bin in the
+//               appropriate structures within the traverser, as a
+//               sub bin, e.g. a bin that may have geometry assigned
+//               to it, and may therefore be rendered.
+//
+//               In most cases, a toplevel bin is the same as a sub
+//               bin, except in the case of a GeomBinGroup, which is a
+//               toplevel bin that contains a number of sub bins.
+////////////////////////////////////////////////////////////////////
+void CullTraverser::
+attach_sub_bin(GeomBin *bin) {
+  if (cull_cat.is_debug()) {
+    cull_cat.debug()
+      << "Attaching sub bin " << *bin << "\n";
+  }
+
+  _sub_bins.insert(SubBins::value_type(bin->get_sort(), bin));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::detach_toplevel_bin
+//       Access: Private
+//  Description: This is intended to be called only by
+//               GeomBin::detach().  It removes the bin from the
+//               appropriate structures within the traverser, as a
+//               toplevel bin.  See attach_toplevel_bin().
+////////////////////////////////////////////////////////////////////
+void CullTraverser::
+detach_toplevel_bin(GeomBin *bin) {
+  if (cull_cat.is_debug()) {
+    cull_cat.debug()
+      << "Detaching toplevel bin " << *bin << "\n";
+  }
+
+  ToplevelBins::iterator tbi = _toplevel_bins.find(bin->get_name());
+  nassertv(tbi != _toplevel_bins.end());
+  _toplevel_bins.erase(tbi);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::detach_sub_bin
+//       Access: Private
+//  Description: This is intended to be called only by
+//               GeomBin::detach().  It removes the bin from the
+//               appropriate structures within the traverser, as a
+//               sub bin.  See attach_sub_bin().
+////////////////////////////////////////////////////////////////////
+void CullTraverser::
+detach_sub_bin(GeomBin *bin) {
+  if (cull_cat.is_debug()) {
+    cull_cat.debug()
+      << "Detaching sub bin " << *bin << "\n";
+  }
+
+  // Remove the bin from its place in the sort order list.  This will
+  // be one of the (possibly several) entries in the multimap with the
+  // same sort value.
+  pair<SubBins::iterator, SubBins::iterator> range;
+  range = _sub_bins.equal_range(bin->get_sort());
+
+  SubBins::iterator sbi;
+  for (sbi = range.first; sbi != range.second; ++sbi) {
+    GeomBin *consider_bin = (*sbi).second;
+    nassertv(consider_bin->get_sort() == bin->get_sort());
+
+    if (consider_bin == bin) {
+      // Here's the position!
+      _sub_bins.erase(sbi);
+      return;
+    }
+  }
+  nassertv(false);
+}

+ 13 - 3
panda/src/cull/cullTraverser.h

@@ -43,6 +43,8 @@ public:
 
 
   INLINE void set_default_bin(GeomBin *bin);
   INLINE void set_default_bin(GeomBin *bin);
   INLINE GeomBin *get_default_bin() const;
   INLINE GeomBin *get_default_bin() const;
+  INLINE bool has_bin(const string &name) const;
+  INLINE GeomBin *get_bin(const string &name) const;
 
 
   virtual void traverse(Node *root, 
   virtual void traverse(Node *root, 
 			const AllAttributesWrapper &initial_state,
 			const AllAttributesWrapper &initial_state,
@@ -92,10 +94,17 @@ public:
 	       const CullLevelState &level_state);
 	       const CullLevelState &level_state);
 
 
 private:
 private:
+  void attach_toplevel_bin(GeomBin *bin);
+  void attach_sub_bin(GeomBin *bin);
+  void detach_toplevel_bin(GeomBin *bin);
+  void detach_sub_bin(GeomBin *bin);
+
   AllAttributesWrapper _initial_state;
   AllAttributesWrapper _initial_state;
 
 
-  typedef set<PT(GeomBin)> Bins;
-  Bins _bins;
+  typedef map<string, PT(GeomBin)> ToplevelBins;
+  typedef multimap<int, PT(GeomBin)> SubBins;
+  ToplevelBins _toplevel_bins;
+  SubBins _sub_bins;
   PT(GeomBin) _default_bin;
   PT(GeomBin) _default_bin;
 
 
   typedef set<PT(CullState), IndirectCompareTo<CullState> > States;
   typedef set<PT(CullState), IndirectCompareTo<CullState> > States;
@@ -128,7 +137,8 @@ public:
 private:
 private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
 
 
-friend class GeomBin;
+  friend class GeomBin;
+  friend class GeomBinGroup;
 };
 };
 
 
 #include "cullTraverser.I"
 #include "cullTraverser.I"

+ 57 - 22
panda/src/cull/geomBin.I

@@ -9,13 +9,39 @@
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomBin::
 INLINE GeomBin::
-GeomBin(const string &name, CullTraverser *traverser, int sort) :
+GeomBin(const string &name) :
   Namable(name) 
   Namable(name) 
 {
 {
   _traverser = (CullTraverser *)NULL;
   _traverser = (CullTraverser *)NULL;
-  if (traverser != (CullTraverser *)NULL) {
-    attach_to(traverser, sort);
-  }
+  _is_attached = false;
+  _sort = 0;
+  _parent = (GeomBin *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBin::get_sort
+//       Access: Public
+//  Description: Returns the sort index associated with this
+//               particular bin.  The CullTraverser will render bins
+//               in order according to their sort index.
+////////////////////////////////////////////////////////////////////
+INLINE int GeomBin::
+get_sort() const {
+  return _sort;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBin::has_traverser
+//       Access: Public
+//  Description: Returns true if the GeomBin is currently attached to
+//               a traverser, false otherwise.  If this is false, and
+//               the bin is not attached to a parent bin
+//               (i.e. has_parent() is also false), don't expect the
+//               bin to be rendered.
+////////////////////////////////////////////////////////////////////
+INLINE bool GeomBin::
+has_traverser() const {
+  return (_traverser != (CullTraverser *)NULL);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -30,31 +56,40 @@ get_traverser() const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomBin::get_sort
+//     Function: GeomBin::has_parent
 //       Access: Public
 //       Access: Public
-//  Description: Returns the sort index associated with this
-//               particular bin.  The CullTraverser will render bins
-//               in order according to their sort index.
+//  Description: Returns true if the bin is a child of some
+//               GeomBinGroup, false if it is a toplevel bin in its
+//               own right.  See GeomBinGroup.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE int GeomBin::
-get_sort() const {
-  return _sort;
+INLINE bool GeomBin::
+has_parent() const {
+  return _parent != (GeomBin *)NULL;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomBin::set_sort
+//     Function: GeomBin::get_parent
 //       Access: Public
 //       Access: Public
-//  Description: Changes the sort index associated with this
-//               particular bin.  The CullTraverser will render bins
-//               in order according to their sort index.
+//  Description: Returns the parent pointer of the GeomBin if the bin
+//               is a child of some GeomBinGropu, or NULL if the bin
+//               does not have a parent.  See GeomBinGroup.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE void GeomBin::
-set_sort(int sort) {
-  if (_traverser != (CullTraverser *)NULL) {
-    attach_to(_traverser, sort);
-  } else {
-    _sort = sort;
-  }
+INLINE GeomBin *GeomBin::
+get_parent() const {
+  return _parent;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBin::is_attached
+//       Access: Public
+//  Description: Returns true if the bin is currently attached to a
+//               CullTraverser, false otherwise.  This should always
+//               be tree if has_traverser() is true, and false if
+//               has_traverser() is false.
+////////////////////////////////////////////////////////////////////
+INLINE bool GeomBin::
+is_attached() const {
+  return _is_attached;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 182 - 41
panda/src/cull/geomBin.cxx

@@ -22,69 +22,188 @@ GeomBin::
 ~GeomBin() {
 ~GeomBin() {
   // We shouldn't be attached to anything when we destruct.  If we
   // We shouldn't be attached to anything when we destruct.  If we
   // are, something went screwy in the reference counting.
   // are, something went screwy in the reference counting.
+  nassertv(!_is_attached);
   nassertv(_traverser == (CullTraverser *)NULL);
   nassertv(_traverser == (CullTraverser *)NULL);
+
+  // We also shouldn't be part of any parent bin.
+  nassertv(_parent == (GeomBin *)NULL);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomBin::attach_to
+//     Function: GeomBin::set_name
 //       Access: Public
 //       Access: Public
-//  Description: Detaches the bin from whichever CullTraverser it is
-//               currently attached to, and attaches it to the
-//               indicated CullTraverser instead, at the indicated
-//               sort level.  The CullTraverser will render all of its
-//               attached GeomBins, in order according to sort level.
+//  Description: Changes the name of the GeomBin, correctly updating
+//               the CullTraverser it's attached to.
+////////////////////////////////////////////////////////////////////
+void GeomBin::
+set_name(const string &name) {
+  if (name == get_name()) {
+    return;
+  }
+
+  // If we're currently attached, we need to need to be unattached
+  // while we change the name--but only if we're a toplevel bin.  A
+  // nested bin doesn't matter.
+  if (is_attached() && !has_parent()) {
+    PT(GeomBin) keep = this;
+
+    nassertv(_traverser != (CullTraverser *)NULL);
+    _traverser->detach_toplevel_bin(this);
+    Namable::set_name(name);
+    _traverser->attach_toplevel_bin(this);
+
+  } else {
+    Namable::set_name(name);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBin::clear_name
+//       Access: Public
+//  Description: Removes the name of the GeomBin.  This also detaches
+//               it (if it is a toplevel bin), and may therefore
+//               inadvertently delete it!  Be very careful.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomBin::
 void GeomBin::
-attach_to(CullTraverser *traverser, int sort) {
-  nassertv(traverser != (CullTraverser *)NULL);
-  PT(GeomBin) keep = detach();
-  _sort = sort;
+clear_name() {
+  PT(GeomBin) keep;
+
+  if (is_attached() && !has_parent()) {
+    cull_cat.warning()
+      << "GeomBin::clear_name() called on an attached GeomBin.\n";
+    keep = detach();
+  }
+
+  Namable::clear_name();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBin::set_sort
+//       Access: Public
+//  Description: Changes the sort index associated with this
+//               particular bin.  The CullTraverser will render bins
+//               in order according to their sort index.
+////////////////////////////////////////////////////////////////////
+void GeomBin::
+set_sort(int sort) {
+  if (sort == _sort) {
+    return;
+  }
+
+  // If we're currently attached, even if we're a nested bin, we need
+  // to be unattached while we adjust the sorting order.
+  if (is_attached()) {
+    PT(GeomBin) keep = this;
+
+    nassertv(_traverser != (CullTraverser *)NULL);
+    _traverser->detach_sub_bin(this);
+    _sort = sort;
+    _traverser->attach_sub_bin(this);
+
+  } else {
+    _sort = sort;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBin::set_traverser
+//       Access: Public
+//  Description: Associates the GeomBin with the indicated
+//               CullTraverser.  A particular bin may only be
+//               associated with one traverser at a time.  This is
+//               normally done only after initially creating the
+//               GeomBin; it is an error to call set_traverser() more
+//               than once on the same bin (without calling
+//               clear_traverser() first).
+//
+//               It is also not necessary (and is an error) to assign
+//               child bins of a GeomBinGroup to a traverser; just
+//               assign the parent bin.
+//
+//               This must be called before the GeomBin can be
+//               rendered; it will thereafter be rendered by the
+//               indicated traverser.
+////////////////////////////////////////////////////////////////////
+void GeomBin::
+set_traverser(CullTraverser *traverser) {
+  if (traverser == (CullTraverser *)NULL) {
+    clear_traverser();
+  }
+
+  nassertv(!is_attached());
+  nassertv(_traverser == (CullTraverser *)NULL);
+
   _traverser = traverser;
   _traverser = traverser;
-  _traverser->_bins.insert(this);
+  attach();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomBin::detach
+//     Function: GeomBin::clear_traverser
 //       Access: Public
 //       Access: Public
-//  Description: Detaches the bin from whichever CullTraverser it is
-//               currently attached to, if any.  The bin will no
-//               longer be rendered.  The return value is a
-//               PT(GeomBin) that refers to the GeomBin itself; the
-//               caller should save this pointer in a local PT
-//               variable to avoid possibly destructing the GeomBin
-//               (since detaching it may remove the last outstanding
-//               reference count).
+//  Description: Disassociates the GeomBin with its current traverser.
+//               The bin will no longer be rendered, and may even be
+//               deleted if you do not immediately save the returned
+//               pointer.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(GeomBin) GeomBin::
 PT(GeomBin) GeomBin::
-detach() {
+clear_traverser() {
   PT(GeomBin) keep = this;
   PT(GeomBin) keep = this;
-  if (_traverser != (CullTraverser *)NULL) {
-    _traverser->_bins.erase(this);
+
+  if (is_attached()) {
+    detach();
+    _traverser = (CullTraverser *)NULL;
   }
   }
-  _traverser = (CullTraverser *)NULL;
+  
   return keep;
   return keep;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomBin::remove_state
-//       Access: Public, Virtual
-//  Description: Disassociates the indicated state from the bin, if it
-//               was previously associated; presumably because a
-//               change in the scene's initial attributes as resulted
-//               in the indicated CullState switching to a new bin.
-//               
-//               Since the initial attributes will remain constant
-//               throughout a given frame, this function will only be
-//               called for GeomBins that save CullStates between
-//               frames; simple GeomBins that empty the entire list of
-//               CullStates upon a call to clear_current_states()
-//               should never see this function.
+//     Function: GeomBin::attach
+//       Access: Protected, Virtual
+//  Description: Formally adds the GeomBin to its indicated Traverser.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomBin::
 void GeomBin::
-remove_state(CullState *) {
-  cull_cat.error()
-    << "remove_state() unexpectedly called for " << get_type() << "\n";
-  nassertv(false);
+attach() {
+  nassertv(has_name());
+  nassertv(_traverser != (CullTraverser *)NULL);
+  nassertv(!_is_attached);
+
+  // In the ordinary case, a bin is both a toplevel bin (visible by
+  // name from the CullTraverser) and a sub bin (directly renderable).
+  if (!has_parent()) {
+    _traverser->attach_toplevel_bin(this);
+  }
+  _traverser->attach_sub_bin(this);
+
+  _is_attached = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBin::detach
+//       Access: Protected, Virtual
+//  Description: Detaches the bin from whichever CullTraverser it is
+//               currently attached to.  The bin will no longer be
+//               rendered.  The return value is a PT(GeomBin) that
+//               refers to the GeomBin itself; the caller should save
+//               this pointer in a local PT variable to avoid possibly
+//               destructing the GeomBin (since detaching it may
+//               remove the last outstanding reference count).
+////////////////////////////////////////////////////////////////////
+PT(GeomBin) GeomBin::
+detach() {
+  nassertr(_is_attached, NULL);
+  nassertr(_traverser != (CullTraverser *)NULL, NULL);
+    
+  PT(GeomBin) keep = this;
+
+  if (!has_parent()) {
+    _traverser->detach_toplevel_bin(this);
+  }
+  _traverser->detach_sub_bin(this);
+
+  _is_attached = false;
+
+  return keep;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -106,3 +225,25 @@ void GeomBin::
 write(ostream &out, int indent_level) const {
 write(ostream &out, int indent_level) const {
   indent(out, indent_level) << *this << "\n";
   indent(out, indent_level) << *this << "\n";
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBin::remove_state
+//       Access: Public, Virtual
+//  Description: Disassociates the indicated state from the bin, if it
+//               was previously associated; presumably because a
+//               change in the scene's initial attributes as resulted
+//               in the indicated CullState switching to a new bin.
+//               
+//               Since the initial attributes will remain constant
+//               throughout a given frame, this function will only be
+//               called for GeomBins that save CullStates between
+//               frames; simple GeomBins that empty the entire list of
+//               CullStates upon a call to clear_current_states()
+//               should never see this function.
+////////////////////////////////////////////////////////////////////
+void GeomBin::
+remove_state(CullState *) {
+  cull_cat.error()
+    << "remove_state() unexpectedly called for " << get_type() << "\n";
+  nassertv(false);
+}

+ 26 - 9
panda/src/cull/geomBin.h

@@ -35,16 +35,29 @@ class CullTraverser;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA GeomBin : public TypedReferenceCount, public Namable {
 class EXPCL_PANDA GeomBin : public TypedReferenceCount, public Namable {
 public:
 public:
-  INLINE GeomBin(const string &name, CullTraverser *traverser = NULL, 
-		 int sort = 0);
+  INLINE GeomBin(const string &name);
   virtual ~GeomBin();
   virtual ~GeomBin();
 
 
-  void attach_to(CullTraverser *traverser, int sort = 0);
-  PT(GeomBin) detach();
+PUBLISHED:
+  void set_name(const string &name);
+  void clear_name();
 
 
-  INLINE CullTraverser *get_traverser() const;
   INLINE int get_sort() const;
   INLINE int get_sort() const;
-  INLINE void set_sort(int sort);
+  void set_sort(int sort);
+
+  void set_traverser(CullTraverser *traverser);
+  INLINE bool has_traverser() const;
+  INLINE CullTraverser *get_traverser() const;
+  PT(GeomBin) clear_traverser();
+
+  INLINE bool has_parent() const;
+  INLINE GeomBin *get_parent() const;
+
+  virtual void output(ostream &out) const;
+  virtual void write(ostream &out, int indent_level = 0) const;
+
+public:
+  INLINE bool is_attached() const;
 
 
   virtual void clear_current_states()=0;
   virtual void clear_current_states()=0;
   virtual void record_current_state(GraphicsStateGuardian *gsg,
   virtual void record_current_state(GraphicsStateGuardian *gsg,
@@ -54,15 +67,17 @@ public:
 
 
   virtual void draw(CullTraverser *trav)=0;
   virtual void draw(CullTraverser *trav)=0;
 
 
-  virtual void output(ostream &out) const;
-  virtual void write(ostream &out, int indent_level = 0) const;
-
 protected:
 protected:
   INLINE void claim_cull_state(CullState *cs);
   INLINE void claim_cull_state(CullState *cs);
   INLINE void disclaim_cull_state(CullState *cs);
   INLINE void disclaim_cull_state(CullState *cs);
 
 
+  virtual void attach();
+  virtual PT(GeomBin) detach();
+
   CullTraverser *_traverser;
   CullTraverser *_traverser;
+  bool _is_attached;
   int _sort;
   int _sort;
+  GeomBin *_parent;
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
@@ -82,6 +97,8 @@ public:
  
  
 private:
 private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
+
+  friend class GeomBinGroup;
 };
 };
 
 
 INLINE ostream &operator << (ostream &out, const GeomBin &bin) {
 INLINE ostream &operator << (ostream &out, const GeomBin &bin) {

+ 6 - 6
panda/src/cull/geomBinAttribute.I

@@ -18,7 +18,7 @@ GeomBinAttribute() {
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomBinAttribute::
 INLINE GeomBinAttribute::
-GeomBinAttribute(GeomBin *bin, int draw_order) {
+GeomBinAttribute(const string &bin, int draw_order) {
   set_on(bin, draw_order);
   set_on(bin, draw_order);
 }
 }
 
 
@@ -29,8 +29,8 @@ GeomBinAttribute(GeomBin *bin, int draw_order) {
 //               geomBin.
 //               geomBin.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void GeomBinAttribute::
 INLINE void GeomBinAttribute::
-set_on(GeomBin *bin, int draw_order) {
-  nassertv(bin != (GeomBin *)NULL);
+set_on(const string &bin, int draw_order) {
+  nassertv(!bin.empty());
   _value = bin;
   _value = bin;
   _draw_order = draw_order;
   _draw_order = draw_order;
   OnOffAttribute::set_on();
   OnOffAttribute::set_on();
@@ -39,13 +39,13 @@ set_on(GeomBin *bin, int draw_order) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomBinAttribute::get_bin
 //     Function: GeomBinAttribute::get_bin
 //       Access: Public
 //       Access: Public
-//  Description: Returns the bin that the GeomBinAttribute
+//  Description: Returns the bin name that the GeomBinAttribute
 //               represents.  It is only valid to call this if is_on()
 //               represents.  It is only valid to call this if is_on()
 //               has returned true.
 //               has returned true.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE PT(GeomBin) GeomBinAttribute::
+INLINE string GeomBinAttribute::
 get_bin() const {
 get_bin() const {
-  nassertr(is_on(), NULL);
+  nassertr(is_on(), string());
   return _value;
   return _value;
 }
 }
 
 

+ 6 - 6
panda/src/cull/geomBinAttribute.cxx

@@ -9,6 +9,8 @@
 #include <graphicsStateGuardianBase.h>
 #include <graphicsStateGuardianBase.h>
 #include <indent.h>
 #include <indent.h>
 
 
+#include <string.h>
+
 TypeHandle GeomBinAttribute::_type_handle;
 TypeHandle GeomBinAttribute::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -56,7 +58,7 @@ set_value_from(const OnOffTransition *other) {
   DCAST_INTO_V(ot, other);
   DCAST_INTO_V(ot, other);
   _value = ot->_value;
   _value = ot->_value;
   _draw_order = ot->_draw_order;
   _draw_order = ot->_draw_order;
-  nassertv(_value != (GeomBin *)NULL);
+  nassertv(!_value.empty());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -69,7 +71,7 @@ compare_values(const OnOffAttribute *other) const {
   const GeomBinAttribute *ot;
   const GeomBinAttribute *ot;
   DCAST_INTO_R(ot, other, false);
   DCAST_INTO_R(ot, other, false);
   if (_value != ot->_value) {
   if (_value != ot->_value) {
-    return (int)(_value - ot->_value);
+    return strcmp(_value.c_str(), ot->_value.c_str());
   }
   }
   return _draw_order - ot->_draw_order;
   return _draw_order - ot->_draw_order;
 }
 }
@@ -81,8 +83,7 @@ compare_values(const OnOffAttribute *other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomBinAttribute::
 void GeomBinAttribute::
 output_value(ostream &out) const {
 output_value(ostream &out) const {
-  nassertv(_value != (GeomBin *)NULL);
-  out << *_value << ":" << _draw_order;
+  out << _value << ":" << _draw_order;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -93,6 +94,5 @@ output_value(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomBinAttribute::
 void GeomBinAttribute::
 write_value(ostream &out, int indent_level) const {
 write_value(ostream &out, int indent_level) const {
-  nassertv(_value != (GeomBin *)NULL);
-  indent(out, indent_level) << *_value << ":" << _draw_order << "\n";
+  indent(out, indent_level) << _value << ":" << _draw_order << "\n";
 }
 }

+ 4 - 4
panda/src/cull/geomBinAttribute.h

@@ -19,10 +19,10 @@
 class EXPCL_PANDA GeomBinAttribute : public OnOffAttribute {
 class EXPCL_PANDA GeomBinAttribute : public OnOffAttribute {
 public:
 public:
   INLINE GeomBinAttribute();
   INLINE GeomBinAttribute();
-  INLINE GeomBinAttribute(GeomBin *bin, int draw_order = 0);
+  INLINE GeomBinAttribute(const string &bin, int draw_order = 0);
 
 
-  INLINE void set_on(GeomBin *bin, int draw_order = 0);
-  INLINE PT(GeomBin) get_bin() const;
+  INLINE void set_on(const string &bin, int draw_order = 0);
+  INLINE string get_bin() const;
   INLINE int get_draw_order() const;
   INLINE int get_draw_order() const;
 
 
   virtual TypeHandle get_handle() const;
   virtual TypeHandle get_handle() const;
@@ -35,7 +35,7 @@ protected:
   virtual void output_value(ostream &out) const;
   virtual void output_value(ostream &out) const;
   virtual void write_value(ostream &out, int indent_level) const;
   virtual void write_value(ostream &out, int indent_level) const;
 
 
-  PT(GeomBin) _value;
+  string _value;
   int _draw_order;
   int _draw_order;
 
 
 public:
 public:

+ 2 - 2
panda/src/cull/geomBinBackToFront.I

@@ -77,7 +77,7 @@ draw(CullTraverser *trav) const {
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomBinBackToFront::
 INLINE GeomBinBackToFront::
-GeomBinBackToFront(const string &name, CullTraverser *traverser, int sort) :
-  GeomBin(name, traverser, sort) 
+GeomBinBackToFront(const string &name) :
+  GeomBin(name) 
 {
 {
 }
 }

+ 3 - 4
panda/src/cull/geomBinBackToFront.h

@@ -24,11 +24,10 @@
 //               without a Z-buffer.
 //               without a Z-buffer.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA GeomBinBackToFront : public GeomBin {
 class EXPCL_PANDA GeomBinBackToFront : public GeomBin {
-public:
-  INLINE GeomBinBackToFront(const string &name, 
-			    CullTraverser *traverser = NULL,
-			    int sort = 0);
+PUBLISHED:
+  INLINE GeomBinBackToFront(const string &name);
 
 
+public:
   virtual void clear_current_states();
   virtual void clear_current_states();
   virtual void record_current_state(GraphicsStateGuardian *gsg,
   virtual void record_current_state(GraphicsStateGuardian *gsg,
 				    CullState *cs, int draw_order,
 				    CullState *cs, int draw_order,

+ 2 - 2
panda/src/cull/geomBinFixed.I

@@ -78,7 +78,7 @@ draw(CullTraverser *trav) const {
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomBinFixed::
 INLINE GeomBinFixed::
-GeomBinFixed(const string &name, CullTraverser *traverser, int sort) :
-  GeomBin(name, traverser, sort) 
+GeomBinFixed(const string &name) :
+  GeomBin(name) 
 {
 {
 }
 }

+ 3 - 4
panda/src/cull/geomBinFixed.h

@@ -21,11 +21,10 @@
 //               specified at each GeomBinTransition.
 //               specified at each GeomBinTransition.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA GeomBinFixed : public GeomBin {
 class EXPCL_PANDA GeomBinFixed : public GeomBin {
-public:
-  INLINE GeomBinFixed(const string &name, 
-		      CullTraverser *traverser = NULL,
-		      int sort = 0);
+PUBLISHED:
+  INLINE GeomBinFixed(const string &name);
 
 
+public:
   virtual void clear_current_states();
   virtual void clear_current_states();
   virtual void record_current_state(GraphicsStateGuardian *gsg,
   virtual void record_current_state(GraphicsStateGuardian *gsg,
 				    CullState *cs, int draw_order,
 				    CullState *cs, int draw_order,

+ 2 - 30
panda/src/cull/geomBinGroup.I

@@ -9,23 +9,11 @@
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomBinGroup::
 INLINE GeomBinGroup::
-GeomBinGroup(const string &name, CullTraverser *traverser, int sort) :
-  GeomBin(name, traverser, sort) 
+GeomBinGroup(const string &name) :
+  GeomBin(name) 
 {
 {
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GeomBinGroup::add_sub_bin
-//       Access: Public
-//  Description: Appends the indicated bin to the end of the sub_bin
-//               list, and returns the new index.
-////////////////////////////////////////////////////////////////////
-INLINE int GeomBinGroup::
-add_sub_bin(GeomBin *sub_bin) {
-  _sub_bins.push_back(sub_bin);
-  return _sub_bins.size() - 1;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomBinGroup::get_num_bins
 //     Function: GeomBinGroup::get_num_bins
 //       Access: Public
 //       Access: Public
@@ -46,19 +34,3 @@ get_bin(int n) {
   nassertr(n >= 0 && n < (int)_sub_bins.size(), NULL);
   nassertr(n >= 0 && n < (int)_sub_bins.size(), NULL);
   return _sub_bins[n];
   return _sub_bins[n];
 }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomBinGroup::remove_bin
-//       Access: Public
-//  Description: Removes the nth bin.  All subsequent index numbers
-//               shift down by one.  The return value is the
-//               just-removed bin, which may be deleted if it is not
-//               immediately saved.
-////////////////////////////////////////////////////////////////////
-INLINE PT(GeomBin) GeomBinGroup::
-remove_bin(int n) {
-  nassertr(n >= 0 && n < (int)_sub_bins.size(), NULL);
-  PT(GeomBin) keep = get_bin(n);
-  _sub_bins.erase(_sub_bins.begin() + n);
-  return keep;
-}

+ 148 - 0
panda/src/cull/geomBinGroup.cxx

@@ -12,6 +12,75 @@
 
 
 TypeHandle GeomBinGroup::_type_handle;
 TypeHandle GeomBinGroup::_type_handle;
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBinGroup::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+GeomBinGroup::
+~GeomBinGroup() {
+  nassertv(!is_attached());
+
+  // Disassociate all of our children before we destruct.
+  SubBins::iterator sbi;
+  for (sbi = _sub_bins.begin(); sbi != _sub_bins.end(); ++sbi) {
+    GeomBin *sub_bin = (*sbi);
+    sub_bin->_parent = (GeomBin *)NULL;
+  }
+  _sub_bins.clear();
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBinGroup::add_sub_bin
+//       Access: Public
+//  Description: Appends the indicated bin to the end of the sub_bin
+//               list, and returns the new index.
+////////////////////////////////////////////////////////////////////
+int GeomBinGroup::
+add_sub_bin(GeomBin *sub_bin) {
+  nassertr(!sub_bin->has_parent(), -1);
+  nassertr(!sub_bin->is_attached(), -1);
+  nassertr(sub_bin->has_name(), -1);
+
+  sub_bin->_parent = this;
+  _sub_bins.push_back(sub_bin);
+
+  if (is_attached()) {
+    sub_bin->_traverser = _traverser;
+    _traverser->attach_sub_bin(sub_bin);
+  }
+
+  return _sub_bins.size() - 1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBinGroup::remove_bin
+//       Access: Public
+//  Description: Removes the nth bin.  All subsequent index numbers
+//               shift down by one.  The return value is the
+//               just-removed bin, which may be deleted if it is not
+//               immediately saved.
+////////////////////////////////////////////////////////////////////
+PT(GeomBin) GeomBinGroup::
+remove_bin(int n) {
+  nassertr(n >= 0 && n < (int)_sub_bins.size(), NULL);
+  PT(GeomBin) sub_bin = get_bin(n);
+  nassertr(sub_bin->get_parent() == this, NULL);
+
+  if (is_attached()) {
+    nassertr(sub_bin->is_attached(), NULL);
+    nassertr(sub_bin->_traverser == _traverser, NULL);
+    _traverser->detach_sub_bin(sub_bin);
+    sub_bin->_traverser = (CullTraverser *)NULL;
+  }
+
+  _sub_bins.erase(_sub_bins.begin() + n);
+  sub_bin->_parent = (GeomBin *)NULL;
+
+  return sub_bin;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomBinGroup::clear_current_states
 //     Function: GeomBinGroup::clear_current_states
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -22,6 +91,13 @@ TypeHandle GeomBinGroup::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomBinGroup::
 void GeomBinGroup::
 clear_current_states() {
 clear_current_states() {
+  // This should never be called for toplevel bins, only sub bins--and
+  // a GeomBinGroup should never be a sub bin.  The function will do
+  // the right thing even if it is called, but this is probably a
+  // mistake.
+  cull_cat.warning()
+    << "GeomBinGroup::clear_current_states() called\n";
+
   SubBins::iterator sbi;
   SubBins::iterator sbi;
   for (sbi = _sub_bins.begin(); sbi != _sub_bins.end(); ++sbi) {
   for (sbi = _sub_bins.begin(); sbi != _sub_bins.end(); ++sbi) {
     (*sbi)->clear_current_states();
     (*sbi)->clear_current_states();
@@ -51,6 +127,13 @@ record_current_state(GraphicsStateGuardian *gsg, CullState *cs,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomBinGroup::
 void GeomBinGroup::
 draw(CullTraverser *trav) {
 draw(CullTraverser *trav) {
+  // This should never be called for toplevel bins, only sub bins--and
+  // a GeomBinGroup should never be a sub bin.  The function will do
+  // the right thing even if it is called, but this is probably a
+  // mistake.
+  cull_cat.warning()
+    << "GeomBinGroup::draw() called\n";
+
   SubBins::iterator sbi;
   SubBins::iterator sbi;
   for (sbi = _sub_bins.begin(); sbi != _sub_bins.end(); ++sbi) {
   for (sbi = _sub_bins.begin(); sbi != _sub_bins.end(); ++sbi) {
     (*sbi)->draw(trav);
     (*sbi)->draw(trav);
@@ -84,3 +167,68 @@ write(ostream &out, int indent_level) const {
 
 
   indent(out, indent_level) << "}\n";
   indent(out, indent_level) << "}\n";
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBinGroup::attach
+//       Access: Protected, Virtual
+//  Description: Formally adds the GeomBin to its indicated Traverser.
+////////////////////////////////////////////////////////////////////
+void GeomBinGroup::
+attach() {
+  nassertv(has_name());
+  nassertv(_traverser != (CullTraverser *)NULL);
+  nassertv(!_is_attached);
+
+  // In the case of a GeomBinGroup, the bin is only a toplevel bin
+  // (visible by name from the CullTraverser), and not a sub bin
+  // (directly renderable).
+  if (!has_parent()) {
+    _traverser->attach_toplevel_bin(this);
+  }
+
+  _is_attached = true;
+
+  // Now attach each of our sub bins.
+  SubBins::const_iterator sbi;
+  for (sbi = _sub_bins.begin(); sbi != _sub_bins.end(); ++sbi) {
+    GeomBin *sub_bin = (*sbi);
+    nassertv(!sub_bin->is_attached());
+    sub_bin->_traverser = _traverser;
+    sub_bin->attach();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBinGroup::detach
+//       Access: Protected, Virtual
+//  Description: Detaches the bin from whichever CullTraverser it is
+//               currently attached to.  The bin will no longer be
+//               rendered.  The return value is a PT(GeomBin) that
+//               refers to the GeomBin itself; the caller should save
+//               this pointer in a local PT variable to avoid possibly
+//               destructing the GeomBin (since detaching it may
+//               remove the last outstanding reference count).
+////////////////////////////////////////////////////////////////////
+PT(GeomBin) GeomBinGroup::
+detach() {
+  nassertr(_is_attached, NULL);
+  nassertr(_traverser != (CullTraverser *)NULL, NULL);
+    
+  PT(GeomBin) keep = this;
+
+  if (!has_parent()) {
+    _traverser->detach_toplevel_bin(this);
+  }
+
+  _is_attached = false;
+
+  // Now detach each of our sub bins.
+  SubBins::const_iterator sbi;
+  for (sbi = _sub_bins.begin(); sbi != _sub_bins.end(); ++sbi) {
+    GeomBin *sub_bin = (*sbi);
+    sub_bin->detach();
+    sub_bin->_traverser = (CullTraverser *)NULL;
+  }
+
+  return keep;
+}

+ 10 - 5
panda/src/cull/geomBinGroup.h

@@ -23,15 +23,16 @@
 //               a given CullState should be assigned to.
 //               a given CullState should be assigned to.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA GeomBinGroup : public GeomBin {
 class EXPCL_PANDA GeomBinGroup : public GeomBin {
-public:
-  INLINE GeomBinGroup(const string &name, CullTraverser *traverser = NULL,
-		      int sort = 0);
+PUBLISHED:
+  INLINE GeomBinGroup(const string &name);
+  virtual ~GeomBinGroup();
 
 
-  INLINE int add_sub_bin(GeomBin *sub_bin);
+  int add_sub_bin(GeomBin *sub_bin);
   INLINE int get_num_bins() const;
   INLINE int get_num_bins() const;
   INLINE GeomBin *get_bin(int n);
   INLINE GeomBin *get_bin(int n);
-  INLINE PT(GeomBin) remove_bin(int n);
+  PT(GeomBin) remove_bin(int n);
 
 
+public:
   virtual int choose_bin(CullState *cs) const=0;
   virtual int choose_bin(CullState *cs) const=0;
 
 
   virtual void clear_current_states();
   virtual void clear_current_states();
@@ -44,6 +45,10 @@ public:
   virtual void output(ostream &out) const;
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level = 0) const;
   virtual void write(ostream &out, int indent_level = 0) const;
 
 
+protected:
+  virtual void attach();
+  virtual PT(GeomBin) detach();
+
 private:
 private:
   typedef vector<PT(GeomBin)> SubBins;
   typedef vector<PT(GeomBin)> SubBins;
   SubBins _sub_bins;
   SubBins _sub_bins;

+ 10 - 5
panda/src/cull/geomBinNormal.cxx

@@ -19,16 +19,21 @@ TypeHandle GeomBinNormal::_type_handle;
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomBinNormal::
 GeomBinNormal::
-GeomBinNormal(const string &name, CullTraverser *traverser, int sort) :
-  GeomBinGroup(name, traverser, sort) 
+GeomBinNormal(const string &name) :
+  GeomBinGroup(name) 
 {
 {
-  add_sub_bin(new GeomBinUnsorted("opaque"));
-  add_sub_bin(new GeomBinBackToFront("transparent"));
+  GeomBinUnsorted *opaque = new GeomBinUnsorted("opaque");
+  GeomBinBackToFront *transparent = new GeomBinBackToFront("transparent");
+  opaque->set_sort(10);
+  transparent->set_sort(20);
+
+  add_sub_bin(opaque);
+  add_sub_bin(transparent);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomBinNormal::Constructor
 //     Function: GeomBinNormal::Constructor
-//       Access: Public
+//       Access: Public, Virtual
 //  Description: Identifies the particular sub-bin the indicated
 //  Description: Identifies the particular sub-bin the indicated
 //               CullState should be assigned to.
 //               CullState should be assigned to.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 3 - 3
panda/src/cull/geomBinNormal.h

@@ -22,10 +22,10 @@
 //               back-to-front.
 //               back-to-front.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA GeomBinNormal : public GeomBinGroup {
 class EXPCL_PANDA GeomBinNormal : public GeomBinGroup {
-public:
-  GeomBinNormal(const string &name, CullTraverser *traverser = NULL,
-		int sort = 0);
+PUBLISHED:
+  GeomBinNormal(const string &name);
 
 
+public:
   virtual int choose_bin(CullState *cs) const;
   virtual int choose_bin(CullState *cs) const;
 
 
 public:
 public:

+ 6 - 6
panda/src/cull/geomBinTransition.I

@@ -18,7 +18,7 @@ GeomBinTransition() {
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomBinTransition::
 INLINE GeomBinTransition::
-GeomBinTransition(GeomBin *bin, int draw_order) : 
+GeomBinTransition(const string &bin, int draw_order) : 
   OnOffTransition(TD_on),
   OnOffTransition(TD_on),
   _value(bin),
   _value(bin),
   _draw_order(draw_order)
   _draw_order(draw_order)
@@ -44,8 +44,8 @@ off() {
 //               bin.
 //               bin.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void GeomBinTransition::
 INLINE void GeomBinTransition::
-set_on(GeomBin *bin, int draw_order) {
-  nassertv(bin != (GeomBin *)NULL);
+set_on(const string &bin, int draw_order) {
+  nassertv(!bin.empty());
   _value = bin;
   _value = bin;
   _draw_order = draw_order;
   _draw_order = draw_order;
   OnOffTransition::set_on();
   OnOffTransition::set_on();
@@ -54,13 +54,13 @@ set_on(GeomBin *bin, int draw_order) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomBinTransition::get_bin
 //     Function: GeomBinTransition::get_bin
 //       Access: Public
 //       Access: Public
-//  Description: Returns the bin that the GeomBinTransition
+//  Description: Returns the bin name that the GeomBinTransition
 //               represents.  It is only valid to call this if is_on()
 //               represents.  It is only valid to call this if is_on()
 //               has returned true.
 //               has returned true.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE PT(GeomBin) GeomBinTransition::
+INLINE string GeomBinTransition::
 get_bin() const {
 get_bin() const {
-  nassertr(is_on(), NULL);
+  nassertr(is_on(), string());
   return _value;
   return _value;
 }
 }
 
 

+ 62 - 6
panda/src/cull/geomBinTransition.cxx

@@ -8,6 +8,8 @@
 
 
 #include <indent.h>
 #include <indent.h>
 
 
+#include <string.h>
+
 TypeHandle GeomBinTransition::_type_handle;
 TypeHandle GeomBinTransition::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -43,7 +45,7 @@ set_value_from(const OnOffTransition *other) {
   DCAST_INTO_V(ot, other);
   DCAST_INTO_V(ot, other);
   _value = ot->_value;
   _value = ot->_value;
   _draw_order = ot->_draw_order; 
   _draw_order = ot->_draw_order; 
-  nassertv(_value != (GeomBin *)NULL);
+  nassertv(!_value.empty());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -56,7 +58,7 @@ compare_values(const OnOffTransition *other) const {
   const GeomBinTransition *ot;
   const GeomBinTransition *ot;
   DCAST_INTO_R(ot, other, false);
   DCAST_INTO_R(ot, other, false);
   if (_value != ot->_value) {
   if (_value != ot->_value) {
-    return (int)(_value - ot->_value);
+    return strcmp(_value.c_str(), ot->_value.c_str());
   }
   }
   return _draw_order - ot->_draw_order;
   return _draw_order - ot->_draw_order;
 }
 }
@@ -68,8 +70,7 @@ compare_values(const OnOffTransition *other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomBinTransition::
 void GeomBinTransition::
 output_value(ostream &out) const {
 output_value(ostream &out) const {
-  nassertv(_value != (GeomBin *)NULL);
-  out << *_value << ":" << _draw_order;
+  out << _value << ":" << _draw_order;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -80,6 +81,61 @@ output_value(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomBinTransition::
 void GeomBinTransition::
 write_value(ostream &out, int indent_level) const {
 write_value(ostream &out, int indent_level) const {
-  nassertv(_value != (GeomBin *)NULL);
-  indent(out, indent_level) << *_value << ":" << _draw_order << "\n";
+  indent(out, indent_level) << _value << ":" << _draw_order << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBinTransition::register_with_factory
+//       Access: Public, Static
+//  Description: Factory method to generate a GeomBinTransition object
+////////////////////////////////////////////////////////////////////
+void GeomBinTransition::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_GeomBinTransition);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBinTransition::write_datagram
+//       Access: Public
+//  Description: Function to write the important information in
+//               the particular object to a Datagram
+////////////////////////////////////////////////////////////////////
+void GeomBinTransition::
+write_datagram(BamWriter *manager, Datagram &me) {
+  OnOffTransition::write_datagram(manager, me);
+  me.add_string(_value);
+  me.add_int32(_draw_order);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBinTransition::make_GeomBinTransition
+//       Access: Public
+//  Description: Factory method to generate a GeomBinTransition object
+////////////////////////////////////////////////////////////////////
+TypedWriteable *GeomBinTransition::
+make_GeomBinTransition(const FactoryParams &params) {
+  GeomBinTransition *me = new GeomBinTransition;
+  BamReader *manager;
+  Datagram packet;
+
+  parse_params(params, manager, packet);
+  DatagramIterator scan(packet);
+
+  me->fillin(scan, manager);
+  return me;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomBinTransition::fillin
+//       Access: Protected
+//  Description: Function that reads out of the datagram (or asks
+//               manager to read) all of the data that is needed to
+//               re-create this object and stores it in the appropiate
+//               place
+////////////////////////////////////////////////////////////////////
+void GeomBinTransition::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  OnOffTransition::fillin(scan, manager);
+  _value = scan.get_string();
+  _draw_order = scan.get_int32();
 }
 }

+ 16 - 6
panda/src/cull/geomBinTransition.h

@@ -16,15 +16,16 @@
 // Description : 
 // Description : 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA GeomBinTransition : public OnOffTransition {
 class EXPCL_PANDA GeomBinTransition : public OnOffTransition {
-public:
+PUBLISHED:
   INLINE GeomBinTransition();
   INLINE GeomBinTransition();
-  INLINE GeomBinTransition(GeomBin *bin, int draw_order = 0);
+  INLINE GeomBinTransition(const string &bin, int draw_order);
   INLINE static GeomBinTransition off();
   INLINE static GeomBinTransition off();
 
 
-  INLINE void set_on(GeomBin *bin, int draw_order = 0);
-  INLINE PT(GeomBin) get_bin() const;
+  INLINE void set_on(const string &bin, int draw_order);
+  INLINE string get_bin() const;
   INLINE int get_draw_order() const;
   INLINE int get_draw_order() const;
-  
+
+public:  
   virtual NodeTransition *make_copy() const;
   virtual NodeTransition *make_copy() const;
   virtual NodeAttribute *make_attrib() const;
   virtual NodeAttribute *make_attrib() const;
 
 
@@ -34,9 +35,18 @@ protected:
   virtual void output_value(ostream &out) const;
   virtual void output_value(ostream &out) const;
   virtual void write_value(ostream &out, int indent_level) const;
   virtual void write_value(ostream &out, int indent_level) const;
 
 
-  PT(GeomBin) _value;
+  string _value;
   int _draw_order;
   int _draw_order;
 
 
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter* manager, Datagram &me);  
+
+  static TypedWriteable *make_GeomBinTransition(const FactoryParams &params);
+
+protected:
+  void fillin(DatagramIterator& scan, BamReader* manager);
+
 public:
 public:
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 2 - 2
panda/src/cull/geomBinUnsorted.I

@@ -9,7 +9,7 @@
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomBinUnsorted::
 INLINE GeomBinUnsorted::
-GeomBinUnsorted(const string &name, CullTraverser *traverser, int sort) :
-  GeomBin(name, traverser, sort) 
+GeomBinUnsorted(const string &name) :
+  GeomBin(name) 
 {
 {
 }
 }

+ 3 - 3
panda/src/cull/geomBinUnsorted.h

@@ -23,11 +23,11 @@
 //               order.
 //               order.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA GeomBinUnsorted : public GeomBin {
 class EXPCL_PANDA GeomBinUnsorted : public GeomBin {
-public:
-  INLINE GeomBinUnsorted(const string &name, CullTraverser *traverser = NULL,
-			 int sort = 0);
+PUBLISHED:
+  INLINE GeomBinUnsorted(const string &name);
   virtual ~GeomBinUnsorted();
   virtual ~GeomBinUnsorted();
 
 
+public:
   virtual void clear_current_states();
   virtual void clear_current_states();
   virtual void record_current_state(GraphicsStateGuardian *gsg,
   virtual void record_current_state(GraphicsStateGuardian *gsg,
 				    CullState *cs, int draw_order,
 				    CullState *cs, int draw_order,

+ 45 - 15
panda/src/doc/eggSyntax.txt

@@ -174,11 +174,18 @@ appear before they are referenced.
     is any of the other options, it specifies the type of transparency
     is any of the other options, it specifies the type of transparency
     to be enabled.
     to be enabled.
 
 
+  <Scalar> bin { bin-name }
+
+    This specifies the bin name order of all polygons with this
+    texture applied, in the absence of a bin name specified on the
+    polygon itself.  See the description for bin under polygon
+    attributes.
+
   <Scalar> draw_order { number }
   <Scalar> draw_order { number }
 
 
     This specifies the fixed drawing order of all polygons with this
     This specifies the fixed drawing order of all polygons with this
     texture applied, in the absence of a drawing order specified on
     texture applied, in the absence of a drawing order specified on
-    the polygon itself.  See the description for draw-order under
+    the polygon itself.  See the description for draw_order under
     polygon attributes.
     polygon attributes.
 
 
   <Transform> { transform-definition }
   <Transform> { transform-definition }
@@ -404,22 +411,39 @@ GEOMETRY ENTRIES
     it to be viewed from either side.
     it to be viewed from either side.
     
     
 
 
+  <Scalar> bin { bin-name }
+
+    It is sometimes important to control the order in which objects
+    are rendered, particularly when transparency is in use.  In Panda,
+    this is achieved via the use of named bins and, within certain
+    kinds of bins, sometimes an explicit draw_order is also used (see
+    below).
+
+    In the normal (state-sorting) mode, Panda renders its geometry by
+    first grouping into one or more named bins, and then rendering the
+    bins in a specified order.  The programmer is free to define any
+    number of bins, named whatever he/she desires.
+
+    This scalar specifies which bin this particular polygon is to be
+    rendered within.  If no bin scalar is given, or if the name given
+    does not match any of the known bins, the polygon will be assigned
+    to the default bin, which renders all opaque geometry sorted by
+    state, followed by all transparent geometry sorted back-to-front.
+
+    See also draw_order, below.
+
+
   <Scalar> draw_order { number }
   <Scalar> draw_order { number }
 
 
-    This defines the fixed drawing order of this polygon.  Drawing
-    order is very important when using certain kinds of transparency.
-    Normally, Performer will draw all opaque objects first, then all
-    transparent objects from back to front.  Sometimes the
-    back-to-front sorting can fail, especially in the case of a small
-    polygon immediately in front of a large polygon.  In this case, it
-    may be necessary to explicitly give the order in which the
-    polygons should be drawn.
+    This works in conjunction with bin, above, to further refine the
+    order in which this polygon is drawn, relative to other geometry
+    in the same bin.  If (and only if) the bin type named in the bin
+    scalar is a GeomBinFixed, this draw_order is used to define the
+    fixed order that all geometry in the same will be rendered, from
+    smaller numbers to larger numbers.
 
 
-    All objects with a given draw-order will be drawn before all
-    objects with a higher draw-order.  Objects with a zero or
-    unspecified draw-order will be drawn first if they are opaque, and
-    in order from back to front if they are transparent.  A negative
-    draw-order is not allowed.
+    If no bin scalar is specified, the default is a bin named "fixed",
+    which is a GeomBinFixed object that always exists by default.
 
 
 
 
 <PointLight> name { 
 <PointLight> name { 
@@ -797,11 +821,17 @@ GROUPING ENTRIES
     affected by fog.  It will be created with the appropriate GeoState
     affected by fog.  It will be created with the appropriate GeoState
     to have fog disabled.
     to have fog disabled.
 
 
+  <Scalar> bin { bin-name }
+
+    This specifies the bin name for all polygons at or below this node
+    that do not explicitly set their own bin.  See the description of
+    bin for geometry attributes, above.
+
   <Scalar> draw_order { number }
   <Scalar> draw_order { number }
 
 
     This specifies the drawing order for all polygons at or below this
     This specifies the drawing order for all polygons at or below this
     node that do not explicitly set their own drawing order.  See the
     node that do not explicitly set their own drawing order.  See the
-    description of draw-order for geometry attributes, above.
+    description of draw_order for geometry attributes, above.
 
 
   <Scalar> write_through { boolean-value }
   <Scalar> write_through { boolean-value }
 
 

+ 64 - 8
panda/src/egg/eggAlphaMode.I

@@ -12,7 +12,7 @@
 INLINE EggAlphaMode::
 INLINE EggAlphaMode::
 EggAlphaMode() {
 EggAlphaMode() {
   _alpha_mode = AM_unspecified;
   _alpha_mode = AM_unspecified;
-  _draw_order = 0.0;
+  _draw_order = 0;
   _has_draw_order = false;
   _has_draw_order = false;
 }
 }
 
 
@@ -66,21 +66,25 @@ get_alpha_mode() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggAlphaMode::set_draw_order
 //     Function: EggAlphaMode::set_draw_order
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description: Sets the "draw-order" flag associated with this
+//               object.  This specifies a particular order in which
+//               objects of this type should be drawn, within the
+//               specified bin.  If a bin is not explicitly specified,
+//               "fixed" is used.  See also set_bin().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void EggAlphaMode::
 INLINE void EggAlphaMode::
-set_draw_order(double order) {
+set_draw_order(int order) {
   _draw_order = order;
   _draw_order = order;
   _has_draw_order = true;
   _has_draw_order = true;
 }
 }
 
 
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggAlphaMode::get_draw_order
 //     Function: EggAlphaMode::get_draw_order
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description: Returns the "draw-order" flag as set for this
+//               particular object.  See set_draw_order().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE double EggAlphaMode::
+INLINE int EggAlphaMode::
 get_draw_order() const {
 get_draw_order() const {
   return _draw_order;
   return _draw_order;
 }
 }
@@ -88,7 +92,8 @@ get_draw_order() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggAlphaMode::has_draw_order
 //     Function: EggAlphaMode::has_draw_order
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description: Returns true if the draw-order flag has been set for
+//               this particular object.  See set_draw_order().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool EggAlphaMode::
 INLINE bool EggAlphaMode::
 has_draw_order() const {
 has_draw_order() const {
@@ -98,13 +103,64 @@ has_draw_order() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggAlphaMode::clear_draw_order
 //     Function: EggAlphaMode::clear_draw_order
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description: Removes the draw-order flag from this particular
+//               object.  See set_draw_order().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void EggAlphaMode::
 INLINE void EggAlphaMode::
 clear_draw_order() {
 clear_draw_order() {
   _has_draw_order = false;
   _has_draw_order = false;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggAlphaMode::set_bin
+//       Access: Public
+//  Description: Sets the "bin" string for this particular object.
+//               This names a particular bin in which the object
+//               should be rendered.  The exact meaning of a bin is
+//               implementation defined, but generally a GeomBin
+//               matching each bin name must also be specifically
+//               added to the rendering engine (e.g. the
+//               CullTraverser) in use for this to work.  See also
+//               set_draw_order().
+////////////////////////////////////////////////////////////////////
+INLINE void EggAlphaMode::
+set_bin(const string &bin) {
+  _bin = bin;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggAlphaMode::get_bin
+//       Access: Public
+//  Description: Returns the bin name that has been set for this
+//               particular object, if any.  See set_bin().
+////////////////////////////////////////////////////////////////////
+INLINE string EggAlphaMode::
+get_bin() const {
+  return _bin;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggAlphaMode::has_bin
+//       Access: Public
+//  Description: Returns true if a bin name has been set for this
+//               particular object.  See set_bin().
+////////////////////////////////////////////////////////////////////
+INLINE bool EggAlphaMode::
+has_bin() const {
+  return !_bin.empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggAlphaMode::clear_bin
+//       Access: Public
+//  Description: Removes the bin name that was set for this particular
+//               object.  See set_bin().
+////////////////////////////////////////////////////////////////////
+INLINE void EggAlphaMode::
+clear_bin() {
+  _bin = string();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggAlphaMode::Inequality Operator
 //     Function: EggAlphaMode::Inequality Operator
 //       Access: Public
 //       Access: Public

+ 12 - 0
panda/src/egg/eggAlphaMode.cxx

@@ -26,6 +26,10 @@ write(ostream &out, int indent_level) const {
     indent(out, indent_level)
     indent(out, indent_level)
       << "<Scalar> draw-order { " << get_draw_order() << " }\n";
       << "<Scalar> draw-order { " << get_draw_order() << " }\n";
   }
   }
+  if (has_bin()) {
+    indent(out, indent_level)
+      << "<Scalar> bin { " << get_bin() << " }\n";
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -46,6 +50,10 @@ operator == (const EggAlphaMode &other) const {
     }
     }
   }
   }
 
 
+  if (_bin != other._bin) {
+    return false;
+  }
+
   return true;
   return true;
 }
 }
 
 
@@ -70,6 +78,10 @@ operator < (const EggAlphaMode &other) const {
     }
     }
   }
   }
 
 
+  if (_bin != other._bin) {
+    return _bin < other._bin;
+  }
+
   return false;
   return false;
 }
 }
 
 

+ 9 - 3
panda/src/egg/eggAlphaMode.h

@@ -40,11 +40,16 @@ public:
   INLINE void set_alpha_mode(AlphaMode mode);
   INLINE void set_alpha_mode(AlphaMode mode);
   INLINE AlphaMode get_alpha_mode() const;
   INLINE AlphaMode get_alpha_mode() const;
 
 
-  INLINE void set_draw_order(double order);
-  INLINE double get_draw_order() const;
+  INLINE void set_draw_order(int order);
+  INLINE int get_draw_order() const;
   INLINE bool has_draw_order() const;
   INLINE bool has_draw_order() const;
   INLINE void clear_draw_order();
   INLINE void clear_draw_order();
 
 
+  INLINE void set_bin(const string &bin);
+  INLINE string get_bin() const;
+  INLINE bool has_bin() const;
+  INLINE void clear_bin();
+
   // Comparison operators are handy.
   // Comparison operators are handy.
   bool operator == (const EggAlphaMode &other) const;
   bool operator == (const EggAlphaMode &other) const;
   INLINE bool operator != (const EggAlphaMode &other) const;
   INLINE bool operator != (const EggAlphaMode &other) const;
@@ -54,8 +59,9 @@ public:
 
 
 private:
 private:
   AlphaMode _alpha_mode;
   AlphaMode _alpha_mode;
-  double _draw_order;
+  int _draw_order;
   bool _has_draw_order;
   bool _has_draw_order;
+  string _bin;
 
 
 
 
 public:
 public:

+ 51 - 0
panda/src/egg/eggGroup.cxx

@@ -265,6 +265,57 @@ write(ostream &out, int indent_level) const {
   indent(out, indent_level) << "}\n";
   indent(out, indent_level) << "}\n";
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::determine_alpha_mode
+//       Access: Public, Virtual
+//  Description: Walks back up the hierarchy, looking for an EggGroup
+//               or EggPrimitive or some such object at this level or
+//               above this group that has an alpha_mode other than
+//               AM_unspecified.  Returns a valid EggAlphaMode pointer
+//               if one is found, or NULL otherwise.
+////////////////////////////////////////////////////////////////////
+EggAlphaMode *EggGroup::
+determine_alpha_mode() {
+  if (get_alpha_mode() != AM_unspecified) {
+    return this;
+  }
+  return EggGroupNode::determine_alpha_mode();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::determine_draw_order
+//       Access: Public, Virtual
+//  Description: Walks back up the hierarchy, looking for an EggGroup
+//               or EggPrimitive or some such object at this level or
+//               above this group that has a draw_order specified.
+//               Returns a valid EggAlphaMode pointer if one is found,
+//               or NULL otherwise.
+////////////////////////////////////////////////////////////////////
+EggAlphaMode *EggGroup::
+determine_draw_order() {
+  if (has_draw_order()) {
+    return this;
+  }
+  return EggGroupNode::determine_draw_order();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::determine_bin
+//       Access: Public, Virtual
+//  Description: Walks back up the hierarchy, looking for an EggGroup
+//               or EggPrimitive or some such object at this level or
+//               above this group that has a bin specified.  Returns a
+//               valid EggAlphaMode pointer if one is found, or NULL
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+EggAlphaMode *EggGroup::
+determine_bin() {
+  if (has_bin()) {
+    return this;
+  }
+  return EggGroupNode::determine_bin();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggGroup::parse_egg
 //     Function: EggGroup::parse_egg
 //       Access: Public
 //       Access: Public

+ 4 - 0
panda/src/egg/eggGroup.h

@@ -77,6 +77,10 @@ public:
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
   bool parse_egg(const string &egg_syntax);
   bool parse_egg(const string &egg_syntax);
 
 
+  virtual EggAlphaMode *determine_alpha_mode();
+  virtual EggAlphaMode *determine_draw_order();
+  virtual EggAlphaMode *determine_bin();
+
   void set_group_type(GroupType type);
   void set_group_type(GroupType type);
   INLINE GroupType get_group_type() const;
   INLINE GroupType get_group_type() const;
 
 

+ 53 - 0
panda/src/egg/eggNode.cxx

@@ -11,6 +11,59 @@
 
 
 TypeHandle EggNode::_type_handle;
 TypeHandle EggNode::_type_handle;
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggNode::determine_alpha_mode
+//       Access: Public, Virtual
+//  Description: Walks back up the hierarchy, looking for an EggGroup
+//               or EggPrimitive or some such object at this level or
+//               above this node that has an alpha_mode other than
+//               AM_unspecified.  Returns a valid EggAlphaMode pointer
+//               if one is found, or NULL otherwise.
+////////////////////////////////////////////////////////////////////
+EggAlphaMode *EggNode::
+determine_alpha_mode() {
+  if (_parent == (EggGroupNode *)NULL) {
+    // Too bad; we're done.
+    return (EggAlphaMode *)NULL;
+  }
+  return _parent->determine_alpha_mode();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggNode::determine_draw_order
+//       Access: Public, Virtual
+//  Description: Walks back up the hierarchy, looking for an EggGroup
+//               or EggPrimitive or some such object at this level or
+//               above this node that has a draw_order specified.
+//               Returns a valid EggAlphaMode pointer if one is found,
+//               or NULL otherwise.
+////////////////////////////////////////////////////////////////////
+EggAlphaMode *EggNode::
+determine_draw_order() {
+  if (_parent == (EggGroupNode *)NULL) {
+    // Too bad; we're done.
+    return (EggAlphaMode *)NULL;
+  }
+  return _parent->determine_draw_order();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggNode::determine_bin
+//       Access: Public, Virtual
+//  Description: Walks back up the hierarchy, looking for an EggGroup
+//               or EggPrimitive or some such object at this level or
+//               above this node that has a bin specified.  Returns a
+//               valid EggAlphaMode pointer if one is found, or NULL
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+EggAlphaMode *EggNode::
+determine_bin() {
+  if (_parent == (EggGroupNode *)NULL) {
+    // Too bad; we're done.
+    return (EggAlphaMode *)NULL;
+  }
+  return _parent->determine_bin();
+}
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
 
 

+ 5 - 0
panda/src/egg/eggNode.h

@@ -16,6 +16,7 @@
 #include <referenceCount.h>
 #include <referenceCount.h>
 
 
 class EggGroupNode;
 class EggGroupNode;
+class EggAlphaMode;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 // 	 Class : EggNode
 // 	 Class : EggNode
@@ -36,6 +37,10 @@ public:
   INLINE bool is_under_transform() const;
   INLINE bool is_under_transform() const;
   INLINE bool is_local_coord() const;
   INLINE bool is_local_coord() const;
 
 
+  virtual EggAlphaMode *determine_alpha_mode();
+  virtual EggAlphaMode *determine_draw_order();
+  virtual EggAlphaMode *determine_bin();
+
   INLINE const LMatrix4d &get_vertex_frame() const;
   INLINE const LMatrix4d &get_vertex_frame() const;
   INLINE const LMatrix4d &get_node_frame() const;
   INLINE const LMatrix4d &get_node_frame() const;
   INLINE const LMatrix4d &get_vertex_frame_inv() const;
   INLINE const LMatrix4d &get_vertex_frame_inv() const;

+ 60 - 0
panda/src/egg/eggPrimitive.cxx

@@ -13,6 +13,66 @@
 TypeHandle EggPrimitive::_type_handle;
 TypeHandle EggPrimitive::_type_handle;
 
 
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggPrimitive::determine_alpha_mode
+//       Access: Public, Virtual
+//  Description: Walks back up the hierarchy, looking for an EggPrimitive
+//               or EggPrimitive or some such object at this level or
+//               above this primitive that has an alpha_mode other than
+//               AM_unspecified.  Returns a valid EggAlphaMode pointer
+//               if one is found, or NULL otherwise.
+////////////////////////////////////////////////////////////////////
+EggAlphaMode *EggPrimitive::
+determine_alpha_mode() {
+  if (get_alpha_mode() != AM_unspecified) {
+    return this;
+  }
+  if (has_texture() && get_texture()->get_alpha_mode() != AM_unspecified) {
+    return get_texture();
+  }
+  return EggNode::determine_alpha_mode();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggPrimitive::determine_draw_order
+//       Access: Public, Virtual
+//  Description: Walks back up the hierarchy, looking for an EggPrimitive
+//               or EggPrimitive or some such object at this level or
+//               above this primitive that has a draw_order specified.
+//               Returns a valid EggAlphaMode pointer if one is found,
+//               or NULL otherwise.
+////////////////////////////////////////////////////////////////////
+EggAlphaMode *EggPrimitive::
+determine_draw_order() {
+  if (has_draw_order()) {
+    return this;
+  }
+  if (has_texture() && get_texture()->has_draw_order()) {
+    return get_texture();
+  }
+  return EggNode::determine_draw_order();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggPrimitive::determine_bin
+//       Access: Public, Virtual
+//  Description: Walks back up the hierarchy, looking for an EggPrimitive
+//               or EggPrimitive or some such object at this level or
+//               above this primitive that has a bin specified.  Returns a
+//               valid EggAlphaMode pointer if one is found, or NULL
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+EggAlphaMode *EggPrimitive::
+determine_bin() {
+  if (has_bin()) {
+    return this;
+  }
+  if (has_texture() && get_texture()->has_bin()) {
+    return get_texture();
+  }
+  return EggNode::determine_bin();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggPrimitive::reverse_vertex_ordering
 //     Function: EggPrimitive::reverse_vertex_ordering
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 4 - 0
panda/src/egg/eggPrimitive.h

@@ -51,6 +51,10 @@ public:
   INLINE EggPrimitive &operator = (const EggPrimitive &copy);
   INLINE EggPrimitive &operator = (const EggPrimitive &copy);
   INLINE ~EggPrimitive();
   INLINE ~EggPrimitive();
 
 
+  virtual EggAlphaMode *determine_alpha_mode();
+  virtual EggAlphaMode *determine_draw_order();
+  virtual EggAlphaMode *determine_bin();
+
   INLINE void set_texture(PT(EggTexture) texture);
   INLINE void set_texture(PT(EggTexture) texture);
   INLINE void clear_texture();
   INLINE void clear_texture();
   INLINE PT(EggTexture) get_texture() const;
   INLINE PT(EggTexture) get_texture() const;

+ 16 - 5
panda/src/egg/parser.yxx

@@ -384,7 +384,10 @@ texture_body:
     }
     }
 
 
   } else if (cmp_nocase_uh(name, "draw_order") == 0) {
   } else if (cmp_nocase_uh(name, "draw_order") == 0) {
-    texture->set_draw_order(value);
+    texture->set_draw_order((int)value);
+
+  } else if (cmp_nocase_uh(name, "bin") == 0) {
+    texture->set_bin(strval);
 
 
   } else if (cmp_nocase_uh(name, "alpha_file") == 0) {
   } else if (cmp_nocase_uh(name, "alpha_file") == 0) {
     texture->set_alpha_file(strval);
     texture->set_alpha_file(strval);
@@ -811,7 +814,9 @@ group_body:
       group->set_alpha_mode(a);
       group->set_alpha_mode(a);
     }
     }
   } else if (cmp_nocase_uh(name, "draw_order") == 0) {
   } else if (cmp_nocase_uh(name, "draw_order") == 0) {
-    group->set_draw_order(value);
+    group->set_draw_order((int)value);
+  } else if (cmp_nocase_uh(name, "bin") == 0) {
+    group->set_bin(strval);
   } else if (cmp_nocase_uh(name, "collide_mask") == 0) {
   } else if (cmp_nocase_uh(name, "collide_mask") == 0) {
     group->set_collide_mask(value);
     group->set_collide_mask(value);
   } else if (cmp_nocase_uh(name, "from_collide_mask") == 0) {
   } else if (cmp_nocase_uh(name, "from_collide_mask") == 0) {
@@ -1325,7 +1330,9 @@ primitive_body:
       primitive->set_alpha_mode(a);
       primitive->set_alpha_mode(a);
     }
     }
   } else if (cmp_nocase_uh(name, "draw_order") == 0) {
   } else if (cmp_nocase_uh(name, "draw_order") == 0) {
-    primitive->set_draw_order(value);
+    primitive->set_draw_order((int)value);
+  } else if (cmp_nocase_uh(name, "bin") == 0) {
+    primitive->set_bin(strval);
   } else {
   } else {
     eggyywarning("Unknown scalar " + name);
     eggyywarning("Unknown scalar " + name);
   }
   }
@@ -1373,7 +1380,9 @@ nurbs_surface_body:
       primitive->set_alpha_mode(a);
       primitive->set_alpha_mode(a);
     }
     }
   } else if (cmp_nocase_uh(name, "draw_order") == 0) {
   } else if (cmp_nocase_uh(name, "draw_order") == 0) {
-    primitive->set_draw_order(value);
+    primitive->set_draw_order((int)value);
+  } else if (cmp_nocase_uh(name, "bin") == 0) {
+    primitive->set_bin(strval);
   } else if (cmp_nocase_uh(name, "u_subdiv") == 0) {
   } else if (cmp_nocase_uh(name, "u_subdiv") == 0) {
     primitive->set_u_subdiv(value);
     primitive->set_u_subdiv(value);
   } else if (cmp_nocase_uh(name, "v_subdiv") == 0) {
   } else if (cmp_nocase_uh(name, "v_subdiv") == 0) {
@@ -1418,7 +1427,9 @@ nurbs_curve_body:
       primitive->set_alpha_mode(a);
       primitive->set_alpha_mode(a);
     }
     }
   } else if (cmp_nocase_uh(name, "draw_order") == 0) {
   } else if (cmp_nocase_uh(name, "draw_order") == 0) {
-    primitive->set_draw_order(value);
+    primitive->set_draw_order((int)value);
+  } else if (cmp_nocase_uh(name, "bin") == 0) {
+    primitive->set_bin(strval);
   } else if (cmp_nocase_uh(name, "subdiv") == 0) {
   } else if (cmp_nocase_uh(name, "subdiv") == 0) {
     primitive->set_subdiv(value);
     primitive->set_subdiv(value);
   } else if (cmp_nocase_uh(name, "type") == 0) {
   } else if (cmp_nocase_uh(name, "type") == 0) {

+ 1 - 1
panda/src/egg2sg/Sources.pp

@@ -4,7 +4,7 @@
 #begin lib_target
 #begin lib_target
   #define TARGET egg2sg
   #define TARGET egg2sg
   #define LOCAL_LIBS \
   #define LOCAL_LIBS \
-    collide egg builder loader chan char switchnode cull
+    cull collide egg builder loader chan char switchnode
 
 
   #define SOURCES \
   #define SOURCES \
     animBundleMaker.cxx animBundleMaker.h characterMaker.cxx \
     animBundleMaker.cxx animBundleMaker.h characterMaker.cxx \

+ 39 - 7
panda/src/egg2sg/eggLoader.cxx

@@ -40,6 +40,7 @@
 #include <decalTransition.h>
 #include <decalTransition.h>
 #include <directRenderTransition.h>
 #include <directRenderTransition.h>
 #include <pruneTransition.h>
 #include <pruneTransition.h>
+#include <depthWriteTransition.h>
 #include <animBundleNode.h>
 #include <animBundleNode.h>
 #include <character.h>
 #include <character.h>
 #include <notify.h>
 #include <notify.h>
@@ -49,6 +50,7 @@
 #include <collisionPlane.h>
 #include <collisionPlane.h>
 #include <collisionSphere.h>
 #include <collisionSphere.h>
 #include <dftraverser.h>
 #include <dftraverser.h>
+#include <geomBinTransition.h>
 
 
 #include <ctype.h>
 #include <ctype.h>
 #include <algorithm>
 #include <algorithm>
@@ -895,17 +897,39 @@ setup_bucket(BuilderBucket &bucket, NamedNode *parent,
   }
   }
 
 
   // Assign the appropriate properties to the bucket.
   // Assign the appropriate properties to the bucket.
-  EggAlphaMode::AlphaMode am = egg_prim->get_alpha_mode();
+
+  // The three "alpha mode"-associated properties--alpha mode, draw
+  // order, and bin--can be defined directly at the primitive, at a
+  // group above the primitive, or an a texture applied to the
+  // primitive.  The EggNode::determine_*() functions can find the
+  // right pointer to the level at which this is actually defined for
+  // a given primitive.
+  EggAlphaMode::AlphaMode am = EggAlphaMode::AM_unspecified;
   bool implicit_alpha = false;
   bool implicit_alpha = false;
+  bool has_draw_order = false;
+  int draw_order = 0;
+  bool has_bin = false;
+  string bin;
+
+  EggAlphaMode *egg_alpha;
+  egg_alpha = egg_prim->determine_alpha_mode();
+  if (egg_alpha != (EggAlphaMode *)NULL) {
+    am = egg_alpha->get_alpha_mode();
+  }
+  egg_alpha = egg_prim->determine_draw_order();
+  if (egg_alpha != (EggAlphaMode *)NULL) {
+    has_draw_order = true;
+    draw_order = egg_alpha->get_draw_order();
+  }
+  egg_alpha = egg_prim->determine_bin();
+  if (egg_alpha != (EggAlphaMode *)NULL) {
+    has_bin = true;
+    bin = egg_alpha->get_bin();
+  }
 
 
   bucket._trans.set_transition(new TextureTransition(TextureTransition::off()));
   bucket._trans.set_transition(new TextureTransition(TextureTransition::off()));
   if (egg_prim->has_texture()) {
   if (egg_prim->has_texture()) {
     PT(EggTexture) egg_tex = egg_prim->get_texture();
     PT(EggTexture) egg_tex = egg_prim->get_texture();
-    // If the primitive didn't specify an alpha mode, allow the
-    // texture to specify one.
-    if (am == EggAlphaMode::AM_unspecified) {
-      am = egg_tex->get_alpha_mode();
-    }
     
     
     const TextureDef &def = _textures[egg_tex];
     const TextureDef &def = _textures[egg_tex];
     if (def._texture != (TextureTransition *)NULL) {
     if (def._texture != (TextureTransition *)NULL) {
@@ -957,7 +981,8 @@ setup_bucket(BuilderBucket &bucket, NamedNode *parent,
     break;
     break;
 
 
   case EggAlphaMode::AM_blend_no_occlude:
   case EggAlphaMode::AM_blend_no_occlude:
-    bucket._trans.set_transition(new TransparencyTransition(TransparencyProperty::M_alpha_sorted));
+    bucket._trans.set_transition(new TransparencyTransition(TransparencyProperty::M_alpha));
+    bucket._trans.set_transition(new DepthWriteTransition(DepthWriteTransition::off()));
     break;
     break;
 
 
   case EggAlphaMode::AM_ms:
   case EggAlphaMode::AM_ms:
@@ -973,6 +998,13 @@ setup_bucket(BuilderBucket &bucket, NamedNode *parent,
     break;
     break;
   }
   }
 
 
+  if (has_bin) {
+    bucket._trans.set_transition(new GeomBinTransition(bin, draw_order));
+
+  } else if (has_draw_order) {
+    bucket._trans.set_transition(new GeomBinTransition("fixed", draw_order));
+  }
+
   if (egg_prim->get_bface_flag()) {
   if (egg_prim->get_bface_flag()) {
     // The primitive is marked with backface culling disabled--we want
     // The primitive is marked with backface culling disabled--we want
     // to see both sides.
     // to see both sides.

+ 16 - 0
panda/src/express/typeHandle.cxx

@@ -667,3 +667,19 @@ get_parent_towards(TypeHandle type) const {
 TypedObject::
 TypedObject::
 ~TypedObject() { 
 ~TypedObject() { 
 }
 }
+
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: TypedObject::get_type
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+TypeHandle TypedObject::
+get_type() const {
+  // Normally, this function should never be called, because it is a
+  // pure virtual function.  If it is called, you probably called
+  // get_type() on a recently-destructed object.
+  express_cat.warning()
+    << "TypedObject::get_type() called!\n";
+  return _type_handle;
+}

+ 8 - 7
panda/src/sgattrib/config_sgattrib.cxx

@@ -186,15 +186,16 @@ ConfigureFn(config_sgattrib) {
 
 
   //Registration of writeable object's creation
   //Registration of writeable object's creation
   //functions with BamReader's factory
   //functions with BamReader's factory
-  RenderRelation::register_with_read_factory();
-  TransformTransition::register_with_read_factory();
-  TextureTransition::register_with_read_factory();
-  TextureApplyTransition::register_with_read_factory();
-  TransparencyTransition::register_with_read_factory();
+  BillboardTransition::register_with_read_factory();
+  ColorMatrixTransition::register_with_read_factory();
   CullFaceTransition::register_with_read_factory();
   CullFaceTransition::register_with_read_factory();
   DecalTransition::register_with_read_factory();
   DecalTransition::register_with_read_factory();
+  DepthWriteTransition::register_with_read_factory();
   PruneTransition::register_with_read_factory();
   PruneTransition::register_with_read_factory();
-  BillboardTransition::register_with_read_factory();
-  ColorMatrixTransition::register_with_read_factory();
+  RenderRelation::register_with_read_factory();
+  TextureApplyTransition::register_with_read_factory();
+  TextureTransition::register_with_read_factory();
+  TransformTransition::register_with_read_factory();
+  TransparencyTransition::register_with_read_factory();
 }
 }
 
 

+ 57 - 0
panda/src/sgattrib/depthWriteTransition.cxx

@@ -6,6 +6,11 @@
 #include "depthWriteTransition.h"
 #include "depthWriteTransition.h"
 #include "depthWriteAttribute.h"
 #include "depthWriteAttribute.h"
 
 
+#include <datagram.h>
+#include <datagramIterator.h>
+#include <bamReader.h>
+#include <bamWriter.h>
+
 TypeHandle DepthWriteTransition::_type_handle;
 TypeHandle DepthWriteTransition::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -28,3 +33,55 @@ NodeAttribute *DepthWriteTransition::
 make_attrib() const {
 make_attrib() const {
   return new DepthWriteAttribute;
   return new DepthWriteAttribute;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: DepthWriteTransition::register_with_factory
+//       Access: Public, Static
+//  Description: Factory method to generate a DepthWriteTransition object
+////////////////////////////////////////////////////////////////////
+void DepthWriteTransition::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_DepthWriteTransition);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DepthWriteTransition::write_datagram
+//       Access: Public
+//  Description: Function to write the important information in
+//               the particular object to a Datagram
+////////////////////////////////////////////////////////////////////
+void DepthWriteTransition::
+write_datagram(BamWriter *manager, Datagram &me) {
+  OnOffTransition::write_datagram(manager, me);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DepthWriteTransition::make_DepthWriteTransition
+//       Access: Public
+//  Description: Factory method to generate a DepthWriteTransition object
+////////////////////////////////////////////////////////////////////
+TypedWriteable *DepthWriteTransition::
+make_DepthWriteTransition(const FactoryParams &params) {
+  DepthWriteTransition *me = new DepthWriteTransition;
+  BamReader *manager;
+  Datagram packet;
+
+  parse_params(params, manager, packet);
+  DatagramIterator scan(packet);
+
+  me->fillin(scan, manager);
+  return me;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DepthWriteTransition::fillin
+//       Access: Protected
+//  Description: Function that reads out of the datagram (or asks
+//               manager to read) all of the data that is needed to
+//               re-create this object and stores it in the appropiate
+//               place
+////////////////////////////////////////////////////////////////////
+void DepthWriteTransition::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  OnOffTransition::fillin(scan, manager);
+}

+ 9 - 0
panda/src/sgattrib/depthWriteTransition.h

@@ -23,6 +23,15 @@ public:
   virtual NodeTransition *make_copy() const;
   virtual NodeTransition *make_copy() const;
   virtual NodeAttribute *make_attrib() const;
   virtual NodeAttribute *make_attrib() const;
 
 
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter* manager, Datagram &me);  
+
+  static TypedWriteable *make_DepthWriteTransition(const FactoryParams &params);
+
+protected:
+  void fillin(DatagramIterator& scan, BamReader* manager);
+
 public:
 public:
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();