Browse Source

implement M_dual

David Rose 23 years ago
parent
commit
2fc1dfb8a3

+ 2 - 16
panda/src/glgsg/glGraphicsStateGuardian.cxx

@@ -3480,7 +3480,6 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
     enable_multisample_alpha_one(false);
     enable_multisample_alpha_one(false);
     enable_multisample_alpha_mask(false);
     enable_multisample_alpha_mask(false);
     enable_blend(true);
     enable_blend(true);
-    enable_alpha_test(false);
     call_glBlendFunc(GL_ZERO, GL_ONE);
     call_glBlendFunc(GL_ZERO, GL_ONE);
     return;
     return;
   }
   }
@@ -3494,7 +3493,6 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
     enable_multisample_alpha_one(false);
     enable_multisample_alpha_one(false);
     enable_multisample_alpha_mask(false);
     enable_multisample_alpha_mask(false);
     enable_blend(true);
     enable_blend(true);
-    enable_alpha_test(false);
     call_glBlendFunc(GL_DST_COLOR, GL_ZERO);
     call_glBlendFunc(GL_DST_COLOR, GL_ZERO);
     return;
     return;
 
 
@@ -3502,7 +3500,6 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
     enable_multisample_alpha_one(false);
     enable_multisample_alpha_one(false);
     enable_multisample_alpha_mask(false);
     enable_multisample_alpha_mask(false);
     enable_blend(true);
     enable_blend(true);
-    enable_alpha_test(false);
     call_glBlendFunc(GL_ONE, GL_ONE);
     call_glBlendFunc(GL_ONE, GL_ONE);
     return;
     return;
 
 
@@ -3510,7 +3507,6 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
     enable_multisample_alpha_one(false);
     enable_multisample_alpha_one(false);
     enable_multisample_alpha_mask(false);
     enable_multisample_alpha_mask(false);
     enable_blend(true);
     enable_blend(true);
-    enable_alpha_test(false);
     call_glBlendFunc(GL_DST_COLOR, GL_ONE);
     call_glBlendFunc(GL_DST_COLOR, GL_ONE);
     return;
     return;
 
 
@@ -3523,10 +3519,12 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
   // No color blend; is there a transparency set?
   // No color blend; is there a transparency set?
   switch (transparency_mode) {
   switch (transparency_mode) {
       case TransparencyAttrib::M_none:
       case TransparencyAttrib::M_none:
+      case TransparencyAttrib::M_binary:
         break;
         break;
     
     
       case TransparencyAttrib::M_alpha:
       case TransparencyAttrib::M_alpha:
       case TransparencyAttrib::M_alpha_sorted:
       case TransparencyAttrib::M_alpha_sorted:
+      case TransparencyAttrib::M_dual:
         // Should we really have an "alpha" and an "alpha_sorted" mode,
         // Should we really have an "alpha" and an "alpha_sorted" mode,
         // like Performer does?  (The difference is that "alpha" is with
         // like Performer does?  (The difference is that "alpha" is with
         // the write to the depth buffer disabled.)  Or should we just use
         // the write to the depth buffer disabled.)  Or should we just use
@@ -3537,30 +3535,19 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
         enable_multisample_alpha_one(false);
         enable_multisample_alpha_one(false);
         enable_multisample_alpha_mask(false);
         enable_multisample_alpha_mask(false);
         enable_blend(true);
         enable_blend(true);
-        enable_alpha_test(false);
         call_glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
         call_glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
         return;
         return;
-
-      case TransparencyAttrib::M_binary:
-        enable_multisample_alpha_one(false);
-        enable_multisample_alpha_mask(false);
-        enable_blend(false);
-        enable_alpha_test(true);
-        call_glAlphaFunc(GL_EQUAL, 1);
-        return;
     
     
       case TransparencyAttrib::M_multisample:
       case TransparencyAttrib::M_multisample:
         enable_multisample_alpha_one(true);
         enable_multisample_alpha_one(true);
         enable_multisample_alpha_mask(true);
         enable_multisample_alpha_mask(true);
         enable_blend(false);
         enable_blend(false);
-        enable_alpha_test(false);
         return;
         return;
     
     
       case TransparencyAttrib::M_multisample_mask:
       case TransparencyAttrib::M_multisample_mask:
         enable_multisample_alpha_one(false);
         enable_multisample_alpha_one(false);
         enable_multisample_alpha_mask(true);
         enable_multisample_alpha_mask(true);
         enable_blend(false);
         enable_blend(false);
-        enable_alpha_test(false);
         return;
         return;
     
     
       default:
       default:
@@ -3573,7 +3560,6 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
   enable_multisample_alpha_one(false);
   enable_multisample_alpha_one(false);
   enable_multisample_alpha_mask(false);
   enable_multisample_alpha_mask(false);
   enable_blend(false);
   enable_blend(false);
-  enable_alpha_test(false);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 4 - 3
panda/src/pgraph/alphaTestAttrib.I

@@ -24,7 +24,8 @@
 //               AlphaTestAttrib object.
 //               AlphaTestAttrib object.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE AlphaTestAttrib::
 INLINE AlphaTestAttrib::
-AlphaTestAttrib(AlphaTestAttrib::PandaCompareFunc mode,float reference_alpha) :
+AlphaTestAttrib(AlphaTestAttrib::PandaCompareFunc mode,
+                float reference_alpha) :
   _mode(mode), _reference_alpha(reference_alpha)
   _mode(mode), _reference_alpha(reference_alpha)
 {
 {
 }
 }
@@ -35,7 +36,7 @@ AlphaTestAttrib(AlphaTestAttrib::PandaCompareFunc mode,float reference_alpha) :
 //  Description: Returns the alpha write mode.
 //  Description: Returns the alpha write mode.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE AlphaTestAttrib::PandaCompareFunc AlphaTestAttrib::
 INLINE AlphaTestAttrib::PandaCompareFunc AlphaTestAttrib::
-get_mode(void) const {
+get_mode() const {
   return _mode;
   return _mode;
 }
 }
 
 
@@ -45,6 +46,6 @@ get_mode(void) const {
 //  Description: Returns the alpha reference value.
 //  Description: Returns the alpha reference value.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE float AlphaTestAttrib::
 INLINE float AlphaTestAttrib::
-get_reference_alpha(void) const {
+get_reference_alpha() const {
   return _reference_alpha;
   return _reference_alpha;
 }
 }

+ 5 - 3
panda/src/pgraph/alphaTestAttrib.cxx

@@ -83,9 +83,11 @@ compare_to_impl(const RenderAttrib *other) const {
   const AlphaTestAttrib *ta;
   const AlphaTestAttrib *ta;
   DCAST_INTO_R(ta, other, 0);
   DCAST_INTO_R(ta, other, 0);
   int compare_result = ((int)_mode - (int)ta->_mode) ;
   int compare_result = ((int)_mode - (int)ta->_mode) ;
-  if(compare_result!=0)
-      return compare_result;
-   else return (int) (255.0f*(_reference_alpha - ta->_reference_alpha));
+  if (compare_result!=0) {
+    return compare_result;
+  } else {
+    return (int) (255.0f*(_reference_alpha - ta->_reference_alpha));
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 4 - 2
panda/src/pgraph/alphaTestAttrib.h

@@ -31,10 +31,12 @@ class FactoryParams;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA AlphaTestAttrib : public RenderAttrib {
 class EXPCL_PANDA AlphaTestAttrib : public RenderAttrib {
 private:
 private:
-  INLINE AlphaTestAttrib(PandaCompareFunc mode = M_always,float reference_alpha = 1.0f);
+  INLINE AlphaTestAttrib(PandaCompareFunc mode = M_always,
+                         float reference_alpha = 1.0f);
 
 
 PUBLISHED:
 PUBLISHED:
-  static CPT(RenderAttrib) make(PandaCompareFunc mode,float reference_alpha);
+  static CPT(RenderAttrib) make(PandaCompareFunc mode,
+                                float reference_alpha);
   INLINE float get_reference_alpha() const;
   INLINE float get_reference_alpha() const;
   INLINE PandaCompareFunc get_mode() const;
   INLINE PandaCompareFunc get_mode() const;
 
 

+ 3 - 0
panda/src/pgraph/config_pgraph.cxx

@@ -18,6 +18,7 @@
 
 
 #include "config_pgraph.h"
 #include "config_pgraph.h"
 
 
+#include "alphaTestAttrib.h"
 #include "ambientLight.h"
 #include "ambientLight.h"
 #include "billboardEffect.h"
 #include "billboardEffect.h"
 #include "camera.h"
 #include "camera.h"
@@ -104,6 +105,7 @@ init_libpgraph() {
   }
   }
   initialized = true;
   initialized = true;
 
 
+  AlphaTestAttrib::init_type();
   AmbientLight::init_type();
   AmbientLight::init_type();
   BillboardEffect::init_type();
   BillboardEffect::init_type();
   Camera::init_type();
   Camera::init_type();
@@ -162,6 +164,7 @@ init_libpgraph() {
   ColorLerpFunctor::init_type();
   ColorLerpFunctor::init_type();
   ColorScaleLerpFunctor::init_type();
   ColorScaleLerpFunctor::init_type();
 
 
+  AlphaTestAttrib::register_with_read_factory();
   AmbientLight::register_with_read_factory();
   AmbientLight::register_with_read_factory();
   BillboardEffect::register_with_read_factory();
   BillboardEffect::register_with_read_factory();
   Camera::register_with_read_factory();
   Camera::register_with_read_factory();

+ 0 - 15
panda/src/pgraph/cullResult.I

@@ -54,18 +54,3 @@ get_bin(int bin_index) {
   }
   }
   return make_new_bin(bin_index);
   return make_new_bin(bin_index);
 }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullResult::add_object
-//       Access: Public
-//  Description: Adds the indicated CullableObject to the appropriate
-//               bin.  The bin becomes the owner of the object
-//               pointer, and will eventually delete it.
-////////////////////////////////////////////////////////////////////
-INLINE void CullResult::
-add_object(CullableObject *object) {
-  nassertv(object->_state != (const RenderState *)NULL);
-  CullBin *bin = get_bin(object->_state->get_bin_index());
-  nassertv(bin != (CullBin *)NULL);
-  bin->add_object(object);
-}

+ 110 - 0
panda/src/pgraph/cullResult.cxx

@@ -18,6 +18,9 @@
 
 
 #include "cullResult.h"
 #include "cullResult.h"
 #include "cullBinManager.h"
 #include "cullBinManager.h"
+#include "alphaTestAttrib.h"
+#include "transparencyAttrib.h"
+#include "renderState.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CullResult::make_next
 //     Function: CullResult::make_next
@@ -44,6 +47,64 @@ make_next() const {
   return new_result;
   return new_result;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::add_object
+//       Access: Public
+//  Description: Adds the indicated CullableObject to the appropriate
+//               bin.  The bin becomes the owner of the object
+//               pointer, and will eventually delete it.
+////////////////////////////////////////////////////////////////////
+void CullResult::
+add_object(CullableObject *object) {
+  // Check to see if there's a special transparency setting.
+  const RenderState *state = object->_state;
+  nassertv(state != (const RenderState *)NULL);
+
+  const TransparencyAttrib *trans = state->get_transparency();
+  if (trans != (const TransparencyAttrib *)NULL) {
+    switch (trans->get_mode()) {
+    case TransparencyAttrib::M_binary:
+      // M_binary is implemented by explicitly setting the alpha test.
+      object->_state = state->compose(get_binary_state());
+      break;
+
+    case TransparencyAttrib::M_dual:
+      {
+        // M_dual is implemented by drawing the opaque parts first,
+        // without transparency, then drawing the transparent parts
+        // later.  This means we must copy the object and add it to
+        // both bins.  We can only do this if we do not have an
+        // explicit bin already applied; otherwise, M_dual falls back
+        // to M_alpha.
+        const CullBinAttrib *bin_attrib = state->get_bin();
+        if (bin_attrib == (CullBinAttrib *)NULL || 
+            bin_attrib->get_bin_name().empty()) {
+          // We make a copy of the object to draw the transparent part
+          // without decals; this gets placed in the transparent bin.
+          CullableObject *transparent_part = new CullableObject(*object);
+          transparent_part->_state = state->compose(get_dual_transparent_state());
+          CullBin *bin = get_bin(transparent_part->_state->get_bin_index());
+          nassertv(bin != (CullBin *)NULL);
+          bin->add_object(transparent_part);
+
+          // Now we can draw the opaque part, with decals.  This will
+          // end up in the opaque bin.
+          object->_state = state->compose(get_dual_opaque_state());
+        }
+      }
+      break;
+
+    default:
+      // Other kinds of transparency need no special handling.
+      break;
+    }
+  }
+  
+  CullBin *bin = get_bin(object->_state->get_bin_index());
+  nassertv(bin != (CullBin *)NULL);
+  bin->add_object(object);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CullResult::finish_cull
 //     Function: CullResult::finish_cull
 //       Access: Public
 //       Access: Public
@@ -119,3 +180,52 @@ make_new_bin(int bin_index) {
 
 
   return bin;
   return bin;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::get_binary_state
+//       Access: Private
+//  Description: Returns a RenderState that applies the effects of
+//               M_binary.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) CullResult::
+get_binary_state() {
+  static CPT(RenderState) state = NULL;
+  if (state == (const RenderState *)NULL) {
+    state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_equal, 1.0f),
+                              RenderState::get_max_priority());
+  }
+  return state;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::get_dual_transparent_state
+//       Access: Private
+//  Description: Returns a RenderState that renders only the
+//               transparent parts of an object, in support of M_dual.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) CullResult::
+get_dual_transparent_state() {
+  static CPT(RenderState) state = NULL;
+  if (state == (const RenderState *)NULL) {
+    state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_less, 1.0f),
+                              RenderState::get_max_priority());
+  }
+  return state;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::get_dual_opaque_state
+//       Access: Private
+//  Description: Returns a RenderState that renders only the
+//               opaque parts of an object, in support of M_dual.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) CullResult::
+get_dual_opaque_state() {
+  static CPT(RenderState) state = NULL;
+  if (state == (const RenderState *)NULL) {
+    state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_equal, 1.0f),
+                              TransparencyAttrib::make(TransparencyAttrib::M_none),
+                              RenderState::get_max_priority());
+  }
+  return state;
+}

+ 5 - 1
panda/src/pgraph/cullResult.h

@@ -53,7 +53,7 @@ public:
 
 
   INLINE CullBin *get_bin(int bin_index);
   INLINE CullBin *get_bin(int bin_index);
 
 
-  INLINE void add_object(CullableObject *object);
+  void add_object(CullableObject *object);
   void finish_cull();
   void finish_cull();
   void draw();
   void draw();
 
 
@@ -63,6 +63,10 @@ public:
 private:
 private:
   CullBin *make_new_bin(int bin_index);
   CullBin *make_new_bin(int bin_index);
 
 
+  static CPT(RenderState) get_binary_state();
+  static CPT(RenderState) get_dual_transparent_state();
+  static CPT(RenderState) get_dual_opaque_state();
+
   GraphicsStateGuardianBase *_gsg;
   GraphicsStateGuardianBase *_gsg;
 
 
   typedef pvector< PT(CullBin) > Bins;
   typedef pvector< PT(CullBin) > Bins;

+ 1 - 1
panda/src/pgraph/cullTraverserData.cxx

@@ -156,7 +156,7 @@ get_fake_view_frustum_cull_state() {
       (ColorAttrib::make_flat(Colorf(1.0f, 0.0f, 0.0f, 1.0f)),
       (ColorAttrib::make_flat(Colorf(1.0f, 0.0f, 0.0f, 1.0f)),
        TextureAttrib::make_off(),
        TextureAttrib::make_off(),
        RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
        RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
-       1000);
+       RenderState::get_max_priority());
   }
   }
   return state;
   return state;
 }
 }

+ 15 - 6
panda/src/pgraph/cullableObject.I

@@ -66,22 +66,31 @@ CullableObject(Geom *geom, const RenderState *state,
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CullableObject::Copy Constructor
 //     Function: CullableObject::Copy Constructor
-//       Access: Private
-//  Description: CullableObjects should not be copied.
+//       Access: Public
+//  Description: Copies the CullableObject, but does not copy its
+//               children (decals).
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CullableObject::
 INLINE CullableObject::
-CullableObject(const CullableObject &copy) {
-  nassertv(false);
+CullableObject(const CullableObject &copy) :
+  _geom(copy._geom),
+  _state(copy._state),
+  _transform(copy._transform),
+  _next((CullableObject *)NULL)
+{
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CullableObject::Copy Assignment Operator
 //     Function: CullableObject::Copy Assignment Operator
 //       Access: Private
 //       Access: Private
-//  Description: CullableObjects should not be copied.
+//       Access: Public
+//  Description: Copies the CullableObject, but does not copy its
+//               children (decals).
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void CullableObject::
 INLINE void CullableObject::
 operator = (const CullableObject &copy) {
 operator = (const CullableObject &copy) {
-  nassertv(false);
+  _geom = copy._geom;
+  _state = copy._state;
+  _transform = copy._transform;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 0 - 1
panda/src/pgraph/cullableObject.h

@@ -46,7 +46,6 @@ public:
                         const TransformState *transform,
                         const TransformState *transform,
                         CullableObject *next = NULL);
                         CullableObject *next = NULL);
     
     
-private:
   INLINE CullableObject(const CullableObject &copy);
   INLINE CullableObject(const CullableObject &copy);
   INLINE void operator = (const CullableObject &copy);
   INLINE void operator = (const CullableObject &copy);
 
 

+ 19 - 0
panda/src/pgraph/renderState.I

@@ -237,6 +237,25 @@ get_fog() const {
   return _fog;
   return _fog;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::get_bin
+//       Access: Public
+//  Description: This function is provided as an optimization, to
+//               speed up the render-time checking for the existance
+//               of a BinAttrib on this state.  It returns a
+//               pointer to the BinAttrib, if there is one, or
+//               NULL if there is not.
+////////////////////////////////////////////////////////////////////
+INLINE const CullBinAttrib *RenderState::
+get_bin() const {
+  if ((_flags & F_checked_bin) == 0) {
+    // We pretend this function is const, even though it transparently
+    // modifies the internal bin cache.
+    ((RenderState *)this)->determine_bin();
+  }
+  return _bin;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::get_transparency
 //     Function: RenderState::get_transparency
 //       Access: Public
 //       Access: Public

+ 35 - 7
panda/src/pgraph/renderState.cxx

@@ -608,6 +608,21 @@ write(ostream &out, int indent_level) const {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::get_max_priority
+//       Access: Published, Static
+//  Description: Returns the maximum priority number (sometimes called
+//               override) that may be set on any node.  This may or
+//               may not be enforced, but the scene graph code assumes
+//               that no priority numbers will be larger than this,
+//               and some effects may not work properly if you use a
+//               larger number.
+////////////////////////////////////////////////////////////////////
+int RenderState::
+get_max_priority() {
+  return 1000000000;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::issue_delta_modify
 //     Function: RenderState::issue_delta_modify
 //       Access: Public
 //       Access: Public
@@ -934,9 +949,8 @@ determine_bin_index() {
   string bin_name;
   string bin_name;
   _draw_order = 0;
   _draw_order = 0;
 
 
-  const RenderAttrib *attrib = get_attrib(CullBinAttrib::get_class_type());
-  if (attrib != (const RenderAttrib *)NULL) {
-    const CullBinAttrib *bin_attrib = DCAST(CullBinAttrib, attrib);
+  const CullBinAttrib *bin_attrib = get_bin();
+  if (bin_attrib != (const CullBinAttrib *)NULL) {
     bin_name = bin_attrib->get_bin_name();
     bin_name = bin_attrib->get_bin_name();
     _draw_order = bin_attrib->get_draw_order();
     _draw_order = bin_attrib->get_draw_order();
   }
   }
@@ -946,13 +960,12 @@ determine_bin_index() {
     // either opaque or transparent, based on the transparency
     // either opaque or transparent, based on the transparency
     // setting.
     // setting.
     bin_name = "opaque";
     bin_name = "opaque";
-    const RenderAttrib *attrib = get_attrib(TransparencyAttrib::get_class_type());
-    if (attrib != (const RenderAttrib *)NULL) {
-      const TransparencyAttrib *trans = DCAST(TransparencyAttrib, attrib);
+    const TransparencyAttrib *trans = get_transparency();
+    if (trans != (const TransparencyAttrib *)NULL) {
       switch (trans->get_mode()) {
       switch (trans->get_mode()) {
       case TransparencyAttrib::M_alpha:
       case TransparencyAttrib::M_alpha:
       case TransparencyAttrib::M_alpha_sorted:
       case TransparencyAttrib::M_alpha_sorted:
-      case TransparencyAttrib::M_binary:
+      case TransparencyAttrib::M_dual:
         // These transparency modes require special back-to-front sorting.
         // These transparency modes require special back-to-front sorting.
         bin_name = "transparent";
         bin_name = "transparent";
         break;
         break;
@@ -988,6 +1001,21 @@ determine_fog() {
   _flags |= F_checked_fog;
   _flags |= F_checked_fog;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::determine_bin
+//       Access: Private
+//  Description: This is the private implementation of get_bin().
+////////////////////////////////////////////////////////////////////
+void RenderState::
+determine_bin() {
+  const RenderAttrib *attrib = get_attrib(CullBinAttrib::get_class_type());
+  _bin = (const CullBinAttrib *)NULL;
+  if (attrib != (const RenderAttrib *)NULL) {
+    _bin = DCAST(CullBinAttrib, attrib);
+  }
+  _flags |= F_checked_bin;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::determine_transparency
 //     Function: RenderState::determine_transparency
 //       Access: Private
 //       Access: Private

+ 8 - 1
panda/src/pgraph/renderState.h

@@ -29,6 +29,7 @@
 
 
 class GraphicsStateGuardianBase;
 class GraphicsStateGuardianBase;
 class FogAttrib;
 class FogAttrib;
+class CullBinAttrib;
 class TransparencyAttrib;
 class TransparencyAttrib;
 class FactoryParams;
 class FactoryParams;
 
 
@@ -92,10 +93,13 @@ PUBLISHED:
   void output(ostream &out) const;
   void output(ostream &out) const;
   void write(ostream &out, int indent_level) const;
   void write(ostream &out, int indent_level) const;
 
 
+  static int get_max_priority();
+
 public:
 public:
   INLINE int get_bin_index() const;
   INLINE int get_bin_index() const;
   INLINE int get_draw_order() const;
   INLINE int get_draw_order() const;
   INLINE const FogAttrib *get_fog() const;
   INLINE const FogAttrib *get_fog() const;
+  INLINE const CullBinAttrib *get_bin() const;
   INLINE const TransparencyAttrib *get_transparency() const;
   INLINE const TransparencyAttrib *get_transparency() const;
 
 
   CPT(RenderState) issue_delta_modify(const RenderState *other, 
   CPT(RenderState) issue_delta_modify(const RenderState *other, 
@@ -111,6 +115,7 @@ private:
   CPT(RenderState) do_invert_compose(const RenderState *other) const;
   CPT(RenderState) do_invert_compose(const RenderState *other) const;
   void determine_bin_index();
   void determine_bin_index();
   void determine_fog();
   void determine_fog();
+  void determine_bin();
   void determine_transparency();
   void determine_transparency();
 
 
   INLINE void set_destructing();
   INLINE void set_destructing();
@@ -179,12 +184,14 @@ private:
   // We also cache the pointer to some critical attribs stored in the
   // We also cache the pointer to some critical attribs stored in the
   // state, if they exist.
   // state, if they exist.
   const FogAttrib *_fog;
   const FogAttrib *_fog;
+  const CullBinAttrib *_bin;
   const TransparencyAttrib *_transparency;
   const TransparencyAttrib *_transparency;
 
 
   enum Flags {
   enum Flags {
     F_checked_bin_index    = 0x0001,
     F_checked_bin_index    = 0x0001,
     F_checked_fog          = 0x0002,
     F_checked_fog          = 0x0002,
-    F_checked_transparency = 0x0004,
+    F_checked_bin          = 0x0004,
+    F_checked_transparency = 0x0008,
     F_is_destructing       = 0x8000,
     F_is_destructing       = 0x8000,
   };
   };
   unsigned short _flags;
   unsigned short _flags;

+ 4 - 0
panda/src/pgraph/transparencyAttrib.cxx

@@ -83,6 +83,10 @@ output(ostream &out) const {
   case M_binary:
   case M_binary:
     out << "binary";
     out << "binary";
     break;
     break;
+
+  case M_dual:
+    out << "dual";
+    break;
   }
   }
 }
 }
 
 

+ 1 - 0
panda/src/pgraph/transparencyAttrib.h

@@ -44,6 +44,7 @@ PUBLISHED:
     M_multisample,      // Source alpha values modified to 1.0 before writing
     M_multisample,      // Source alpha values modified to 1.0 before writing
     M_multisample_mask, // Source alpha values not modified
     M_multisample_mask, // Source alpha values not modified
     M_binary,           // Only writes pixels with alpha = 1.0
     M_binary,           // Only writes pixels with alpha = 1.0
+    M_dual,             // 2-pass: draws opaque, then draws transparent
   };
   };
 
 
 private:
 private: