Quellcode durchsuchen

*** empty log message ***

David Rose vor 25 Jahren
Ursprung
Commit
b5441ee6de

+ 24 - 1
panda/src/chan/animGroup.cxx

@@ -57,7 +57,30 @@ get_child(int n) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AnimGroupa::get_value_type
+//     Function: AnimGroup::find_child
+//       Access: Public
+//  Description: Returns the first descendant found with the indicated
+//               name, or NULL if no such descendant exists.
+////////////////////////////////////////////////////////////////////
+AnimGroup *AnimGroup::
+find_child(const string &name) const {
+  Children::const_iterator ci;
+  for (ci = _children.begin(); ci != _children.end(); ++ci) {
+    AnimGroup *child = (*ci);
+    if (child->get_name() == name) {
+      return child;
+    }
+    AnimGroup *result = child->find_child(name);
+    if (result != (AnimGroup *)NULL) {
+      return result;
+    }
+  }
+
+  return (AnimGroup *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimGroup::get_value_type
 //       Access: Public, Virtual
 //  Description: Returns the TypeHandle associated with the ValueType
 //               we are concerned with.  This is provided to allow a

+ 1 - 0
panda/src/chan/animGroup.h

@@ -36,6 +36,7 @@ public:
 
   int get_num_children() const;
   AnimGroup *get_child(int n) const;
+  AnimGroup *find_child(const string &name) const;
 
   virtual TypeHandle get_value_type() const;
 

+ 2 - 0
panda/src/chan/movingPart.h

@@ -49,9 +49,11 @@ public:
     return get_class_type();
   }
   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+PUBLISHED:
   static TypeHandle get_class_type() {
     return _type_handle;
   }
+public:
   static void init_type() {
     MovingPartBase::init_type();
     register_type(_type_handle, SwitchType::get_part_type_name(),

+ 2 - 0
panda/src/chan/movingPartBase.h

@@ -57,9 +57,11 @@ public:
     return get_class_type();
   }
   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+PUBLISHED:
   static TypeHandle get_class_type() {
     return _type_handle;
   }
+public:
   static void init_type() {
     PartGroup::init_type();
     register_type(_type_handle, "MovingPartBase",

+ 2 - 0
panda/src/chan/movingPartMatrix.h

@@ -43,9 +43,11 @@ public:
     return get_class_type();
   }
   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+PUBLISHED:
   static TypeHandle get_class_type() {
     return _type_handle;
   }
+public:
   static void init_type() {
     MovingPart<ACMatrixSwitchType>::init_type();
     AnimChannelFixed<ACMatrixSwitchType>::init_type();

+ 23 - 0
panda/src/chan/partGroup.cxx

@@ -98,6 +98,29 @@ get_child(int n) const {
   return _children[n];
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PartGroup::find_child
+//       Access: Public
+//  Description: Returns the first descendant found with the indicated
+//               name, or NULL if no such descendant exists.
+////////////////////////////////////////////////////////////////////
+PartGroup *PartGroup::
+find_child(const string &name) const {
+  Children::const_iterator ci;
+  for (ci = _children.begin(); ci != _children.end(); ++ci) {
+    PartGroup *child = (*ci);
+    if (child->get_name() == name) {
+      return child;
+    }
+    PartGroup *result = child->find_child(name);
+    if (result != (PartGroup *)NULL) {
+      return result;
+    }
+  }
+
+  return (PartGroup *)NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PartGroup::get_value_type
 //       Access: Public, Virtual

+ 6 - 5
panda/src/chan/partGroup.h

@@ -53,9 +53,15 @@ public:
   virtual PartGroup *make_copy() const;
   PartGroup *copy_subgraph() const;
 
+PUBLISHED:
   int get_num_children() const;
   PartGroup *get_child(int n) const;
+  PartGroup *find_child(const string &name) const;
 
+  virtual void write(ostream &out, int indent_level) const;
+  virtual void write_with_value(ostream &out, int indent_level) const;
+
+public:
   virtual TypeHandle get_value_type() const;
 
   void sort_descendants();
@@ -63,9 +69,6 @@ public:
 		       const PartGroup *parent,
 		       int hierarchy_match_flags = 0) const;
 
-  virtual void write(ostream &out, int indent_level) const;
-  virtual void write_with_value(ostream &out, int indent_level) const;
-
   virtual void do_update(PartBundle *root, PartGroup *parent,
 			 bool parent_changed, bool anim_changed);
 
@@ -99,8 +102,6 @@ public:
     return get_class_type();
   }
   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-PUBLISHED:
   static TypeHandle get_class_type() {
     return _type_handle;
   }

+ 2 - 2
panda/src/cull/cullTraverser.cxx

@@ -220,8 +220,8 @@ traverse(Node *root,
     rel_from_camera = LMatrix4f::ident_mat();
   }
 
-  fc_traverse(root, rel_from_camera, *this, NullAttributeWrapper(), 
-	      level_state, _gsg, _graph_type);
+  fc_traverse(_arc_chain, root, rel_from_camera, *this,
+	      NullAttributeWrapper(), level_state, _gsg, _graph_type);
 
   if (is_initial) {
     draw();

+ 6 - 6
panda/src/glgsg/glGraphicsStateGuardian.cxx

@@ -555,7 +555,7 @@ render_frame(const AllAttributesWrapper &initial_state) {
 ////////////////////////////////////////////////////////////////////
 void GLGraphicsStateGuardian::
 render_scene(Node *root, ProjectionNode *projnode,
-         const AllAttributesWrapper &initial_state) {
+	     const AllAttributesWrapper &initial_state) {
 #ifdef GSG_VERBOSE
   _pass_number = 0;
   glgsg_cat.debug()
@@ -584,9 +584,9 @@ render_scene(Node *root, ProjectionNode *projnode,
 ////////////////////////////////////////////////////////////////////
 void GLGraphicsStateGuardian::
 render_subgraph(RenderTraverser *traverser,
-        Node *subgraph, ProjectionNode *projnode,
-        const AllAttributesWrapper &initial_state,
-        const AllTransitionsWrapper &net_trans) {
+		Node *subgraph, ProjectionNode *projnode,
+		const AllAttributesWrapper &initial_state,
+		const AllTransitionsWrapper &net_trans) {
   // Calling activate() frequently seems to be intolerably expensive
   // on some platforms.  We'll limit ourselves for now to calling it
   // only during the clear().
@@ -662,8 +662,8 @@ render_subgraph(RenderTraverser *traverser,
 ////////////////////////////////////////////////////////////////////
 void GLGraphicsStateGuardian::
 render_subgraph(RenderTraverser *traverser, Node *subgraph, 
-        const AllAttributesWrapper &initial_state,
-        const AllTransitionsWrapper &net_trans) {
+		const AllAttributesWrapper &initial_state,
+		const AllTransitionsWrapper &net_trans) {
 #ifdef GSG_VERBOSE
   glgsg_cat.debug()
     << "begin subgraph (pass " << ++_pass_number 

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

@@ -4,7 +4,7 @@
 #begin lib_target
   #define TARGET sgmanip
   #define LOCAL_LIBS \
-    dgraph loader sgraphutil sgattrib sgraph linmath lerp
+    cull dgraph loader sgraphutil sgattrib sgraph linmath lerp
 
   #define SOURCES \
     config_sgmanip.cxx config_sgmanip.h findApproxLevel.I \

+ 51 - 30
panda/src/sgmanip/nodePath.I

@@ -3,19 +3,6 @@
 // 
 ////////////////////////////////////////////////////////////////////
 
-#include <transformTransition.h>
-#include <colorMatrixTransition.h>
-#include <alphaTransformTransition.h>
-#include <colorTransition.h>
-#include <textureTransition.h>
-#include <fogTransition.h>
-#include <compose_matrix.h>
-#include <renderModeTransition.h>
-#include <cullFaceTransition.h>
-#include <transparencyTransition.h>
-#include <billboardTransition.h>
-#include <pruneTransition.h>
-#include <namedNode.h>
 
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::ForwardIterator::Constructor
@@ -287,13 +274,13 @@ get_num_nodes() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: NodePath::get_bottom_node
+//     Function: NodePath::node
 //       Access: Public
 //  Description: Returns the bottom node of the path, or NULL if the
 //               path is empty.
 ////////////////////////////////////////////////////////////////////
 INLINE Node *NodePath::
-get_bottom_node() const {
+node() const {
   if (_head == (ArcComponent *)NULL) {
     // A singleton or empty list.
     return _top_node;
@@ -302,26 +289,13 @@ get_bottom_node() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: NodePath::node
-//       Access: Public
-//  Description: A synonym of get_bottom_node(), this returns the
-//               bottom node of the path, or NULL if the path is
-//               empty.  It's redefined for brevity because this
-//               function will be called fairly often.
-////////////////////////////////////////////////////////////////////
-INLINE Node *NodePath::
-node() const {
-  return get_bottom_node();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NodePath::get_bottom_arc
+//     Function: NodePath::arc
 //       Access: Public
 //  Description: Returns the bottom arc of the path, or NULL if the
 //               path is empty or is a singleton.
 ////////////////////////////////////////////////////////////////////
 INLINE NodeRelation *NodePath::
-get_bottom_arc() const {
+arc() const {
   if (_head == (ArcComponent *)NULL) {
     // A singleton or empty list.
     return (NodeRelation *)NULL;
@@ -1176,6 +1150,33 @@ has_color() const {
   return _head->_arc->has_transition(ColorTransition::get_class_type());
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::clear_bin
+//       Access: Public
+//  Description: Completely removes any bin adjustment that may have
+//               been set via set_bin() from this particular arc.
+////////////////////////////////////////////////////////////////////
+INLINE void NodePath::
+clear_bin() {
+  nassertv(has_arcs());
+  nassertv(_head != (ArcComponent *)NULL);
+  _head->_arc->clear_transition(TextureTransition::get_class_type());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::has_bin
+//       Access: Public
+//  Description: Returns true if the arc has been assigned to the a
+//               particular rendering bin via set_bin(), false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool NodePath::
+has_bin() const {
+  nassertr(has_arcs(), false);
+  nassertr(_head != (ArcComponent *)NULL, false);
+  return _head->_arc->has_transition(GeomBinTransition::get_class_type());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::clear_texture
 //       Access: Public
@@ -1449,3 +1450,23 @@ INLINE void NodePath::
 hide_collision_solids() {
   find_all_matches("**/+CollisionNode").hide();
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::get_bottom_node
+//       Access: Public
+//  Description: This function is deprecated.  Use node() instead.
+////////////////////////////////////////////////////////////////////
+INLINE Node *NodePath::
+get_bottom_node() const {
+  return node();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::get_bottom_arc
+//       Access: Public
+//  Description: This function is deprecated.  Use arc() instead.
+////////////////////////////////////////////////////////////////////
+INLINE NodeRelation *NodePath::
+get_bottom_arc() const {
+  return arc();
+}

+ 78 - 0
panda/src/sgmanip/nodePath.cxx

@@ -1879,6 +1879,84 @@ get_color() const {
   return Colorf(0.0, 0.0, 0.0, 0.0);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::set_bin
+//       Access: Public
+//  Description: Assigns the geometry at this level and below to the
+//               named rendering bin.  It is the user's responsibility
+//               to ensure that such a bin already exists, either via
+//               the cull-bin Configrc variable, or by explicitly
+//               creating a GeomBin of the appropriate type at
+//               runtime.
+//
+//               There are two default bins created when Panda is
+//               started: "default" and "fixed".  Normally, all
+//               geometry is assigned to "default" unless specified
+//               otherwise.  This bin renders opaque geometry in
+//               state-sorted order, followed by transparent geometry
+//               sorted back-to-front.  If any geometry is assigned to
+//               "fixed", this will be rendered following all the
+//               geometry in "default", in the order specified by
+//               draw_order for each piece of geometry so assigned.
+//
+//               The draw_order parameter is meaningful only for
+//               GeomBinFixed type bins, e.g. "fixed".  Other kinds of
+//               bins ignore it.
+////////////////////////////////////////////////////////////////////
+void NodePath::
+set_bin(const string &bin_name, int draw_order, int priority) {
+  nassertv(has_arcs());
+  nassertv(_head != (ArcComponent *)NULL);
+
+  GeomBinTransition *bin_trans = new GeomBinTransition(bin_name, draw_order);
+  _head->_arc->set_transition(bin_trans, priority);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::get_bin_name
+//       Access: Public
+//  Description: Returns the name of the bin that this particular arc
+//               was assigned to via set_bin(), or the empty string if
+//               no bin was assigned.  See set_bin() and has_bin().
+////////////////////////////////////////////////////////////////////
+string NodePath::
+get_bin_name() const {
+  nassertr(has_arcs(), string());
+  nassertr(_head != (ArcComponent *)NULL, string());
+
+  const GeomBinTransition *bt;
+  if (get_transition_into(bt, _head->_arc)) {
+    if (bt->is_on()) {
+      return bt->get_bin();
+    }
+  }
+
+  return string();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::get_bin_draw_order
+//       Access: Public
+//  Description: Returns the drawing order associated with the bin
+//               that this particular arc was assigned to via
+//               set_bin(), or 0 if no bin was assigned.  See
+//               set_bin() and has_bin().
+////////////////////////////////////////////////////////////////////
+int NodePath::
+get_bin_draw_order() const {
+  nassertr(has_arcs(), 0);
+  nassertr(_head != (ArcComponent *)NULL, 0);
+
+  const GeomBinTransition *bt;
+  if (get_transition_into(bt, _head->_arc)) {
+    if (bt->is_on()) {
+      return bt->get_draw_order();
+    }
+  }
+
+  return 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::set_texture
 //       Access: Public

+ 26 - 2
panda/src/sgmanip/nodePath.h

@@ -15,6 +15,20 @@
 #include <allTransitionsWrapper.h>
 #include <renderRelation.h>
 #include <dataRelation.h>
+#include <transformTransition.h>
+#include <colorMatrixTransition.h>
+#include <alphaTransformTransition.h>
+#include <colorTransition.h>
+#include <textureTransition.h>
+#include <fogTransition.h>
+#include <compose_matrix.h>
+#include <renderModeTransition.h>
+#include <cullFaceTransition.h>
+#include <transparencyTransition.h>
+#include <billboardTransition.h>
+#include <geomBinTransition.h>
+#include <pruneTransition.h>
+#include <namedNode.h>
 
 #include <map>
 
@@ -140,9 +154,8 @@ PUBLISHED:
   NodeRelation *get_arc(int index) const;
 
   Node *get_top_node() const;
-  INLINE Node *get_bottom_node() const;
   INLINE Node *node() const;
-  INLINE NodeRelation *get_bottom_arc() const;
+  INLINE NodeRelation *arc() const;
 
 
   // Methods to manage the disconnected NodePaths that can result if
@@ -380,6 +393,12 @@ PUBLISHED:
   INLINE void clear_color();
   INLINE bool has_color() const;
   Colorf get_color() const;
+
+  void set_bin(const string &bin_name, int draw_order, int priority = 0);
+  INLINE void clear_bin();
+  INLINE bool has_bin() const;
+  string get_bin_name() const;
+  int get_bin_draw_order() const;
   
   void set_texture(Texture *tex, int priority = 0);
   void set_texture_off(int priority = 0);
@@ -432,6 +451,11 @@ PUBLISHED:
   PT(BoundingVolume) get_bounds() const;
   void write_bounds(ostream &out) const;
 
+  // Deprecated functions.  These will go away soon.
+  INLINE Node *get_bottom_node() const;
+  INLINE NodeRelation *get_bottom_arc() const;
+
+
 public:
   // This is a supporting class for passing the list of arcs to wrt().
   class ForwardIterator {

+ 2 - 4
panda/src/sgraph/renderTraverser.I

@@ -108,7 +108,7 @@ get_graph_type() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void RenderTraverser::
 mark_forward_arc(NodeRelation *arc) {
-  _arc_chain.push_back(arc);
+  // This is now done by the FrustumCullTraverser.
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -120,7 +120,5 @@ mark_forward_arc(NodeRelation *arc) {
 ////////////////////////////////////////////////////////////////////
 INLINE void RenderTraverser::
 mark_backward_arc(NodeRelation *arc) {
-  nassertv(!_arc_chain.empty());
-  nassertv(_arc_chain.back() == arc);
-  _arc_chain.pop_back();
+  // This is now done by the FrustumCullTraverser.
 }

+ 2 - 2
panda/src/sgraphutil/directRenderTraverser.cxx

@@ -97,8 +97,8 @@ traverse(Node *root,
     rel_from_camera = LMatrix4f::ident_mat();
   }
 
-  fc_traverse(root, rel_from_camera, *this, render_state, level_state,
-	      _gsg, _graph_type);
+  fc_traverse(_arc_chain, root, rel_from_camera, *this,
+	      render_state, level_state, _gsg, _graph_type);
 
   if (level_state._decal_mode && 
       root->is_of_type(GeomNode::get_class_type())) {

+ 7 - 12
panda/src/sgraphutil/frustumCullTraverser.I

@@ -18,12 +18,13 @@
 ////////////////////////////////////////////////////////////////////
 template<class Visitor, class LevelState>
 FrustumCullTraverser<Visitor, LevelState>::
-FrustumCullTraverser(Node *root, const LMatrix4f &rel_from_camera,
-		     Visitor &visitor,
+FrustumCullTraverser(ArcChain &arc_chain, Node *root, 
+		     const LMatrix4f &rel_from_camera, Visitor &visitor,
 		     const AttributeWrapper &initial_render_state,
 		     const LevelState &initial_level_state,
 		     GraphicsStateGuardian *gsg, 
 		     TypeHandle graph_type) :
+  _arc_chain(arc_chain),
   _visitor(visitor),
   _initial_render_state(initial_render_state),
   _gsg(gsg),
@@ -64,7 +65,6 @@ FrustumCullTraverser(Node *root, const LMatrix4f &rel_from_camera,
   traverse(root, _initial_render_state, level_state, local_frustum, false);
 
   _view_frustum = NULL;
-  nassertv(_arc_stack.empty());
 }
 
 
@@ -86,7 +86,8 @@ traverse(NodeRelation *arc, AttributeWrapper render_state,
   nassertv(arc->get_child() != (Node *)NULL);
 
   bool carry_on = true;
-  bool pushed_arc_stack = false;
+
+  _arc_chain.push_back(arc);
 
   // First, if we're performing view-frustum culling, check the
   // bounding volume associated with this arc (which bounds all of its
@@ -95,10 +96,6 @@ traverse(NodeRelation *arc, AttributeWrapper render_state,
   if (_view_frustum != (GeometricBoundingVolume *)NULL) {
     // If this arc's child has multiple parents, we need to save the
     // arc on the arc stack, so we can unambiguously wrt().
-    if (arc->get_child()->get_num_parents(_graph_type) > 1) {
-      _arc_stack.push_back(arc);
-      pushed_arc_stack = true;
-    }
 
     if (!all_in) {
       // Now test for intersection with the bounding volume.
@@ -162,7 +159,7 @@ traverse(NodeRelation *arc, AttributeWrapper render_state,
 
 	NodeTransitionWrapper ntw(TransformTransition::get_class_type());
 	wrt(_gsg->get_current_projection_node(),
-	    arc->get_child(), _arc_stack.begin(), _arc_stack.end(),
+	    arc->get_child(), _arc_chain.begin(), _arc_chain.end(),
 	    ntw, _graph_type);
 	
 	const TransformTransition *tt;
@@ -201,9 +198,7 @@ traverse(NodeRelation *arc, AttributeWrapper render_state,
     }
   }
 
-  if (pushed_arc_stack) {
-    _arc_stack.pop_back();
-  }
+  _arc_chain.pop_back();
 }
 
 

+ 7 - 9
panda/src/sgraphutil/frustumCullTraverser.h

@@ -13,6 +13,7 @@
 #include <typeHandle.h>
 #include <geometricBoundingVolume.h>
 #include <graphicsStateGuardian.h>
+#include <arcChain.h>
 
 
 ///////////////////////////////////////////////////////////////////
@@ -28,8 +29,8 @@ public:
   typedef TYPENAME Visitor::TransitionWrapper TransitionWrapper;
   typedef TYPENAME Visitor::AttributeWrapper AttributeWrapper;
 
-  FrustumCullTraverser(Node *root, const LMatrix4f &rel_from_camera,
-		       Visitor &visitor,
+  FrustumCullTraverser(ArcChain &arc_chain, Node *root, 
+		       const LMatrix4f &rel_from_camera, Visitor &visitor,
 		       const AttributeWrapper &initial_render_state,
 		       const LevelState &initial_level_state,
 		       GraphicsStateGuardian *gsg, 
@@ -47,6 +48,7 @@ protected:
 		GeometricBoundingVolume *local_frustum, 
 		bool all_in);
 
+  ArcChain &_arc_chain;
   Visitor &_visitor;
   AttributeWrapper _initial_render_state;
   GraphicsStateGuardian *_gsg;
@@ -57,22 +59,18 @@ protected:
   // coordinate space.  If we are not performing view-frustum culling,
   // this will be a NULL pointer.
   PT(GeometricBoundingVolume) _view_frustum;
-
-  // This is a list of arcs we have passed so we can perform
-  // unambiguous wrt's.
-  typedef vector<NodeRelation *> ArcStack;
-  ArcStack _arc_stack;
 };
 
 // Convenience function.
 template<class Visitor, class AttributeWrapper, class LevelState>
 INLINE void
-fc_traverse(Node *root, const LMatrix4f &rel_from_camera, Visitor &visitor,
+fc_traverse(ArcChain &arc_chain, Node *root, 
+	    const LMatrix4f &rel_from_camera, Visitor &visitor,
 	    const AttributeWrapper &initial_render_state, 
 	    const LevelState &initial_level_state,
 	    GraphicsStateGuardian *gsg, TypeHandle graph_type) {
   FrustumCullTraverser<Visitor, LevelState> 
-    fct(root, rel_from_camera, visitor, initial_render_state, 
+    fct(arc_chain, root, rel_from_camera, visitor, initial_render_state, 
 	initial_level_state, gsg, graph_type);
 }
 

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

@@ -4,7 +4,7 @@
 #begin lib_target
   #define TARGET text
   #define LOCAL_LIBS \
-    putil gobj sgattrib graph sgraph linmath sgraphutil pnmimage gsgbase \
+    cull putil gobj sgattrib graph sgraph linmath sgraphutil pnmimage gsgbase \
     mathutil
 
   #define SOURCES \

+ 59 - 1
panda/src/text/textNode.I

@@ -784,6 +784,60 @@ get_shadow() const {
   return _shadow_offset;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TextNode::set_bin
+//       Access: Public
+//  Description: Names the GeomBin that the TextNode geometry should
+//               be assigned to.  If this is set, then a
+//               GeomBinTransition will be created to explicitly place
+//               each component in the named bin.
+//
+//               The draw_order value will also be passed to each
+//               GeomBinTransition as appropriate; this is
+//               particularly useful if this names a GeomBinFixed,
+//               e.g. "fixed".
+////////////////////////////////////////////////////////////////////
+INLINE void TextNode::
+set_bin(const string &bin) {
+  _bin = bin;
+  rebuild(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextNode::clear_bin
+//       Access: Public
+//  Description: Removes the effect of a previous call to
+//               set_bin().  Text will be drawn in whatever bin
+//               it would like to be drawn in, with no explicit
+//               ordering.
+////////////////////////////////////////////////////////////////////
+INLINE void TextNode::
+clear_bin() {
+  _bin = string();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextNode::has_bin
+//       Access: Public
+//  Description: Returns true if an explicit drawing bin has been
+//               set via set_bin(), false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool TextNode::
+has_bin() const {
+  return !_bin.empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextNode::get_bin
+//       Access: Public
+//  Description: Returns the drawing bin set with set_bin(), or empty
+//               string if no bin has been set.
+////////////////////////////////////////////////////////////////////
+INLINE const string &TextNode::
+get_bin() const {
+  return _bin;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TextNode::set_draw_order
 //       Access: Public
@@ -791,6 +845,10 @@ get_shadow() const {
 //               TextMaker.  This is actually the draw order of the
 //               card and frame.  The shadow is drawn at
 //               _draw_order+1, and the text at _draw_order+2.
+//
+//               This affects the sorting order assigned to the arcs
+//               as they are created, and also is passed to whatever
+//               bin may be assigned via set_bin().
 ////////////////////////////////////////////////////////////////////
 INLINE void TextNode::
 set_draw_order(int draw_order) {
@@ -801,7 +859,7 @@ set_draw_order(int draw_order) {
 ////////////////////////////////////////////////////////////////////
 //     Function: TextNode::get_draw_order
 //       Access: Public
-//  Description: 
+//  Description: Returns the drawing order set with set_draw_order().
 ////////////////////////////////////////////////////////////////////
 INLINE int TextNode::
 get_draw_order() const {

+ 26 - 1
panda/src/text/textNode.cxx

@@ -18,6 +18,7 @@
 #include <billboardTransition.h>
 #include <notify.h>
 #include <sceneGraphReducer.h>
+#include <geomBinTransition.h>
 #include <indent.h>
 
 #include <stdio.h>
@@ -309,10 +310,14 @@ write(ostream &out, int indent_level) const {
       << "shadow of color " << _shadow_color << " at " 
       << _shadow_offset << "\n";
   }
+  if (has_bin()) {
+    indent(out, indent_level)
+      << "bin is " << _bin << "\n";
+  }
   indent(out, indent_level)
     << "draw order is " << _draw_order << ", "
     << _draw_order + 1 << ", " << _draw_order + 2 << "\n";
-
+    
   LVecBase3f scale, hpr, trans;
   if (decompose_matrix(_transform, scale, hpr, trans, _coordinate_system)) {
   indent(out, indent_level)
@@ -418,6 +423,11 @@ do_rebuild() {
     }
   }
 
+  if (has_bin()) {
+    text_arc->set_transition
+      (new GeomBinTransition(_bin, _draw_order + 2));
+  }
+
   // Save the bounding-box information about the text in a form
   // friendly to the user.
   _num_rows = num_rows;
@@ -445,6 +455,11 @@ do_rebuild() {
       shadow_arc->set_transition
 	(new TransparencyTransition(TransparencyProperty::M_alpha));
     }
+
+    if (has_bin()) {
+      shadow_arc->set_transition
+	(new GeomBinTransition(_bin, _draw_order + 1));
+    }
   }
 
   if (has_frame()) {
@@ -456,6 +471,11 @@ do_rebuild() {
       frame_arc->set_transition
 	(new TransparencyTransition(TransparencyProperty::M_alpha));
     }
+
+    if (has_bin()) {
+      frame_arc->set_transition
+	(new GeomBinTransition(_bin, _draw_order + 1));
+    }
   }
 
   if (has_card()) {
@@ -473,6 +493,11 @@ do_rebuild() {
     if (has_card_texture()) {
       card_arc->set_transition(new TextureTransition(_card_texture));
     }
+
+    if (has_bin()) {
+      card_arc->set_transition
+	(new GeomBinTransition(_bin, _draw_order));
+    }
   }
   
   // Now flatten our hierarchy to get rid of the transforms we put in,

+ 6 - 0
panda/src/text/textNode.h

@@ -123,6 +123,11 @@ PUBLISHED:
   INLINE bool has_shadow() const;
   INLINE LVecBase2f get_shadow() const;
 
+  INLINE void set_bin(const string &bin);
+  INLINE void clear_bin();
+  INLINE bool has_bin() const;
+  INLINE const string &get_bin() const;
+
   INLINE void set_draw_order(int draw_order);
   INLINE int get_draw_order() const;
 
@@ -235,6 +240,7 @@ private:
   LVector2f _card_ul, _card_lr;
   LVector2f _shadow_offset;
 
+  string _bin;
   int _draw_order;
 
   LMatrix4f _transform;