Browse Source

ColorBlendAttrib: support separate alpha mode and dual-src blend. bam 6.42

rdb 9 years ago
parent
commit
f0cd1ce315

+ 9 - 0
panda/src/display/graphicsStateGuardian.I

@@ -684,6 +684,15 @@ get_max_color_targets() const {
   return _max_color_targets;
   return _max_color_targets;
 }
 }
 
 
+/**
+ * Returns true if dual source (incoming1_color and incoming1_alpha) blend
+ * operands are supported by this GSG.
+ */
+INLINE bool GraphicsStateGuardian::
+get_supports_dual_source_blending() const {
+  return _supports_dual_source_blending;
+}
+
 /**
 /**
  * Deprecated.  Use get_max_color_targets() instead, which returns the exact
  * Deprecated.  Use get_max_color_targets() instead, which returns the exact
  * same value.
  * same value.

+ 1 - 0
panda/src/display/graphicsStateGuardian.cxx

@@ -246,6 +246,7 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
 
 
   // Assume a maximum of 1 render target in absence of MRT.
   // Assume a maximum of 1 render target in absence of MRT.
   _max_color_targets = 1;
   _max_color_targets = 1;
+  _supports_dual_source_blending = false;
 
 
   _supported_geom_rendering = 0;
   _supported_geom_rendering = 0;
 
 

+ 3 - 0
panda/src/display/graphicsStateGuardian.h

@@ -172,6 +172,7 @@ PUBLISHED:
 
 
   INLINE int get_max_color_targets() const;
   INLINE int get_max_color_targets() const;
   INLINE int get_maximum_simultaneous_render_targets() const;
   INLINE int get_maximum_simultaneous_render_targets() const;
+  INLINE bool get_supports_dual_source_blending() const;
 
 
   MAKE_PROPERTY(max_vertices_per_array, get_max_vertices_per_array);
   MAKE_PROPERTY(max_vertices_per_array, get_max_vertices_per_array);
   MAKE_PROPERTY(max_vertices_per_primitive, get_max_vertices_per_primitive);
   MAKE_PROPERTY(max_vertices_per_primitive, get_max_vertices_per_primitive);
@@ -217,6 +218,7 @@ PUBLISHED:
   MAKE_PROPERTY(supports_timer_query, get_supports_timer_query);
   MAKE_PROPERTY(supports_timer_query, get_supports_timer_query);
   MAKE_PROPERTY(timer_queries_active, get_timer_queries_active);
   MAKE_PROPERTY(timer_queries_active, get_timer_queries_active);
   MAKE_PROPERTY(max_color_targets, get_max_color_targets);
   MAKE_PROPERTY(max_color_targets, get_max_color_targets);
+  MAKE_PROPERTY(supports_dual_source_blending, get_supports_dual_source_blending);
 
 
   INLINE ShaderModel get_shader_model() const;
   INLINE ShaderModel get_shader_model() const;
   INLINE void set_shader_model(ShaderModel shader_model);
   INLINE void set_shader_model(ShaderModel shader_model);
@@ -609,6 +611,7 @@ protected:
   bool _supports_indirect_draw;
   bool _supports_indirect_draw;
 
 
   int _max_color_targets;
   int _max_color_targets;
+  bool _supports_dual_source_blending;
 
 
   int  _supported_geom_rendering;
   int  _supported_geom_rendering;
   bool _color_scale_via_lighting;
   bool _color_scale_via_lighting;

+ 56 - 31
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -3766,43 +3766,24 @@ do_issue_blending() {
     }
     }
   }
   }
 
 
-  const ColorBlendAttrib *target_color_blend = DCAST(ColorBlendAttrib, _target_rs->get_attrib_def(ColorBlendAttrib::get_class_slot()));
-  CPT(ColorBlendAttrib) color_blend = target_color_blend;
-  ColorBlendAttrib::Mode color_blend_mode = target_color_blend->get_mode();
+  const ColorBlendAttrib *color_blend;
+  _target_rs->get_attrib_def(color_blend);
+  ColorBlendAttrib::Mode color_blend_mode = color_blend->get_mode();
 
 
-  const TransparencyAttrib *target_transparency = DCAST(TransparencyAttrib, _target_rs->get_attrib_def(TransparencyAttrib::get_class_slot()));
+  const TransparencyAttrib *target_transparency;
+  _target_rs->get_attrib_def(target_transparency);
   TransparencyAttrib::Mode transparency_mode = target_transparency->get_mode();
   TransparencyAttrib::Mode transparency_mode = target_transparency->get_mode();
 
 
   // Is there a color blend set?
   // Is there a color blend set?
   if (color_blend_mode != ColorBlendAttrib::M_none) {
   if (color_blend_mode != ColorBlendAttrib::M_none) {
     set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
     set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
-
-    switch (color_blend_mode) {
-    case ColorBlendAttrib::M_add:
-      set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
-      break;
-
-    case ColorBlendAttrib::M_subtract:
-      set_render_state(D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
-      break;
-
-    case ColorBlendAttrib::M_inv_subtract:
-      set_render_state(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT);
-      break;
-
-    case ColorBlendAttrib::M_min:
-      set_render_state(D3DRS_BLENDOP, D3DBLENDOP_MIN);
-      break;
-
-    case ColorBlendAttrib::M_max:
-      set_render_state(D3DRS_BLENDOP, D3DBLENDOP_MAX);
-      break;
-    }
-
-    set_render_state(D3DRS_SRCBLEND,
-        get_blend_func(color_blend->get_operand_a()));
-    set_render_state(D3DRS_DESTBLEND,
-        get_blend_func(color_blend->get_operand_b()));
+    set_render_state(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+    set_render_state(D3DRS_BLENDOP, get_blend_mode(color_blend_mode));
+    set_render_state(D3DRS_BLENDOPALPHA, get_blend_mode(color_blend->get_alpha_mode()));
+    set_render_state(D3DRS_SRCBLEND, get_blend_func(color_blend->get_operand_a()));
+    set_render_state(D3DRS_DESTBLEND, get_blend_func(color_blend->get_operand_b()));
+    set_render_state(D3DRS_SRCBLENDALPHA, get_blend_func(color_blend->get_alpha_operand_a()));
+    set_render_state(D3DRS_DESTBLENDALPHA, get_blend_func(color_blend->get_alpha_operand_b()));
     return;
     return;
   }
   }
 
 
@@ -3817,6 +3798,7 @@ do_issue_blending() {
   case TransparencyAttrib::M_multisample_mask:
   case TransparencyAttrib::M_multisample_mask:
   case TransparencyAttrib::M_dual:
   case TransparencyAttrib::M_dual:
     set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
     set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
+    set_render_state(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
     set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
     set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
     set_render_state(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
     set_render_state(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
     set_render_state(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
     set_render_state(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
@@ -3824,6 +3806,7 @@ do_issue_blending() {
 
 
   case TransparencyAttrib::M_premultiplied_alpha:
   case TransparencyAttrib::M_premultiplied_alpha:
     set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
     set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
+    set_render_state(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
     set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
     set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
     set_render_state(D3DRS_SRCBLEND, D3DBLEND_ONE);
     set_render_state(D3DRS_SRCBLEND, D3DBLEND_ONE);
     set_render_state(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
     set_render_state(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
@@ -4052,6 +4035,33 @@ get_light_color(Light *light) const {
   return *(D3DCOLORVALUE *)cf.get_data();
   return *(D3DCOLORVALUE *)cf.get_data();
 }
 }
 
 
+/**
+ * Maps from ColorBlendAttrib::Mode to D3DBLENDOP vaule.
+ */
+D3DBLENDOP DXGraphicsStateGuardian9::
+get_blend_mode(ColorBlendAttrib::Mode mode) {
+  switch (mode) {
+  case ColorBlendAttrib::M_add:
+    return D3DBLENDOP_ADD;
+
+  case ColorBlendAttrib::M_subtract:
+    return D3DBLENDOP_SUBTRACT;
+
+  case ColorBlendAttrib::M_inv_subtract:
+    return D3DBLENDOP_REVSUBTRACT;
+
+  case ColorBlendAttrib::M_min:
+    return D3DBLENDOP_MIN;
+
+  case ColorBlendAttrib::M_max:
+    return D3DBLENDOP_MAX;
+  }
+
+  dxgsg9_cat.error()
+    << "Unknown color blend mode " << (int)mode << endl;
+  return D3DBLENDOP_ADD;
+}
+
 /**
 /**
  * Maps from ColorBlendAttrib::Operand to D3DBLEND value.
  * Maps from ColorBlendAttrib::Operand to D3DBLEND value.
  */
  */
@@ -4106,6 +4116,21 @@ get_blend_func(ColorBlendAttrib::Operand operand) {
 
 
   case ColorBlendAttrib::O_incoming_color_saturate:
   case ColorBlendAttrib::O_incoming_color_saturate:
     return D3DBLEND_SRCALPHASAT;
     return D3DBLEND_SRCALPHASAT;
+
+  case ColorBlendAttrib::O_incoming1_color:
+    return D3DBLEND_SRCCOLOR2;
+
+  case ColorBlendAttrib::O_one_minus_incoming1_color:
+    return D3DBLEND_INVSRCCOLOR2;
+
+  case ColorBlendAttrib::O_incoming1_alpha:
+    // Not supported by DX.
+    return D3DBLEND_SRCCOLOR2;
+
+  case ColorBlendAttrib::O_one_minus_incoming1_alpha:
+    // Not supported by DX.
+    return D3DBLEND_INVSRCCOLOR2;
+
   }
   }
 
 
   dxgsg9_cat.error()
   dxgsg9_cat.error()

+ 1 - 0
panda/src/dxgsg9/dxGraphicsStateGuardian9.h

@@ -217,6 +217,7 @@ protected:
   const D3DCOLORVALUE &get_light_color(Light *light) const;
   const D3DCOLORVALUE &get_light_color(Light *light) const;
   INLINE static D3DTRANSFORMSTATETYPE get_tex_mat_sym(int stage_index);
   INLINE static D3DTRANSFORMSTATETYPE get_tex_mat_sym(int stage_index);
 
 
+  static D3DBLENDOP get_blend_mode(ColorBlendAttrib::Mode mode);
   static D3DBLEND get_blend_func(ColorBlendAttrib::Operand operand);
   static D3DBLEND get_blend_func(ColorBlendAttrib::Operand operand);
   void report_texmgr_stats();
   void report_texmgr_stats();
 
 

+ 4 - 0
panda/src/gles2gsg/gles2gsg.h

@@ -123,6 +123,10 @@ typedef char GLchar;
 #define GL_MAX_DRAW_BUFFERS GL_MAX_DRAW_BUFFERS_NV
 #define GL_MAX_DRAW_BUFFERS GL_MAX_DRAW_BUFFERS_NV
 #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE
 #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE
 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE
 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE
+#define GL_SRC1_COLOR GL_SRC1_COLOR_EXT
+#define GL_ONE_MINUS_SRC1_COLOR GL_ONE_MINUS_SRC1_COLOR_EXT
+#define GL_SRC1_ALPHA GL_SRC1_ALPHA_EXT
+#define GL_ONE_MINUS_SRC1_ALPHA GL_ONE_MINUS_SRC1_ALPHA_EXT
 
 
 // For GLES 3 compat - need a better solution for this
 // For GLES 3 compat - need a better solution for this
 #define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x1
 #define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x1

+ 11 - 0
panda/src/gles2gsg/panda_esgl2ext.h

@@ -430,6 +430,17 @@ typedef struct __GLsync *GLsync;
  * EXT extension tokens
  * EXT extension tokens
  *------------------------------------------------------------------------*/
  *------------------------------------------------------------------------*/
 
 
+#ifndef GL_EXT_blend_func_extended
+#define GL_EXT_blend_func_extended 1
+#define GL_SRC1_COLOR_EXT                                       0x88F9
+#define GL_SRC1_ALPHA_EXT                                       0x8589
+#define GL_ONE_MINUS_SRC1_COLOR_EXT                             0x88FA
+#define GL_ONE_MINUS_SRC1_ALPHA_EXT                             0x88FB
+#define GL_SRC_ALPHA_SATURATE_EXT                               0x0308
+#define GL_LOCATION_INDEX_EXT                                   0x930F
+#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT                     0x88FC
+#endif
+
 /* GL_EXT_blend_minmax */
 /* GL_EXT_blend_minmax */
 #ifndef GL_EXT_blend_minmax
 #ifndef GL_EXT_blend_minmax
 #define GL_MIN_EXT                                              0x8007
 #define GL_MIN_EXT                                              0x8007

+ 159 - 21
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -129,16 +129,23 @@ null_glActiveTexture(GLenum gl_texture_stage) {
 
 
 #ifdef OPENGLES_2
 #ifdef OPENGLES_2
 #define _glBlendEquation glBlendEquation
 #define _glBlendEquation glBlendEquation
+#define _glBlendEquationSeparate glBlendEquationSeparate
+#define _glBlendFuncSeparate glBlendFuncSeparate
 #define _glBlendColor glBlendColor
 #define _glBlendColor glBlendColor
 #else
 #else
 static void APIENTRY
 static void APIENTRY
 null_glBlendEquation(GLenum) {
 null_glBlendEquation(GLenum) {
 }
 }
-#endif
+
+static void APIENTRY
+null_glBlendFuncSeparate(GLenum src, GLenum dest, GLenum, GLenum) {
+  glBlendFunc(src, dest);
+}
 
 
 static void APIENTRY
 static void APIENTRY
 null_glBlendColor(GLclampf, GLclampf, GLclampf, GLclampf) {
 null_glBlendColor(GLclampf, GLclampf, GLclampf, GLclampf) {
 }
 }
+#endif
 
 
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
 // We have a default shader that will be applied when there isn't any shader
 // We have a default shader that will be applied when there isn't any shader
@@ -2284,29 +2291,115 @@ reset() {
   }
   }
 #endif
 #endif
 
 
-  // In OpenGL ES 2.x, this is supported in the core.
-#ifndef OPENGLES_2
-  _glBlendEquation = NULL;
-  bool supports_blend_equation = false;
+#ifdef OPENGLES_1
+  // In OpenGL ES 1, blending is supported via extensions.
+  if (has_extension("GL_OES_blend_subtract")) {
+    _glBlendEquation = (PFNGLBLENDEQUATIONPROC)
+      get_extension_func("glBlendEquationOES");
+
+    if (_glBlendEquation == NULL) {
+      _glBlendEquation = null_glBlendEquation;
+      GLCAT.warning()
+        << "BlendEquationOES advertised as supported by OpenGL ES runtime, but "
+           "could not get pointer to extension function.\n";
+    }
+  } else {
+    _glBlendEquation = null_glBlendEquation;
+  }
+
+  if (has_extension("GL_OES_blend_equation_separate")) {
+    _glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEOESPROC)
+      get_extension_func("glBlendEquationSeparateOES");
+
+    if (_glBlendEquation == NULL) {
+      _supports_blend_equation_separate = false;
+      GLCAT.warning()
+        << "BlendEquationSeparateOES advertised as supported by OpenGL ES "
+           "runtime, but could not get pointer to extension function.\n";
+    } else {
+      _supports_blend_equation_separate = true;
+    }
+  } else {
+    _supports_blend_equation_separate = false;
+    _glBlendEquationSeparate = NULL;
+  }
+
+  if (has_extension("GL_OES_blend_func_separate")) {
+    _glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEOESPROC)
+      get_extension_func("glBlendFuncSeparateOES");
+
+    if (_glBlendFuncSeparate == NULL) {
+      _glBlendFuncSeparate = null_glBlendFuncSeparate;
+      GLCAT.warning()
+        << "BlendFuncSeparateOES advertised as supported by OpenGL ES runtime, but "
+           "could not get pointer to extension function.\n";
+    }
+  } else {
+    _glBlendFuncSeparate = null_glBlendFuncSeparate;
+  }
+
+#elif defined(OPENGLES)
+  // In OpenGL ES 2.x and above, this is supported in the core.
+  _supports_blend_equation_separate = false;
+
+#else
   if (is_at_least_gl_version(1, 2)) {
   if (is_at_least_gl_version(1, 2)) {
-    supports_blend_equation = true;
     _glBlendEquation = (PFNGLBLENDEQUATIONPROC)
     _glBlendEquation = (PFNGLBLENDEQUATIONPROC)
       get_extension_func("glBlendEquation");
       get_extension_func("glBlendEquation");
-  } else if (has_extension("GL_OES_blend_subtract")) {
-    supports_blend_equation = true;
-    _glBlendEquation = (PFNGLBLENDEQUATIONPROC)
-      get_extension_func("glBlendEquationOES");
+
   } else if (has_extension("GL_EXT_blend_minmax")) {
   } else if (has_extension("GL_EXT_blend_minmax")) {
-    supports_blend_equation = true;
     _glBlendEquation = (PFNGLBLENDEQUATIONPROC)
     _glBlendEquation = (PFNGLBLENDEQUATIONPROC)
       get_extension_func("glBlendEquationEXT");
       get_extension_func("glBlendEquationEXT");
+
+  } else {
+    _glBlendEquation = null_glBlendEquation;
   }
   }
-  if (supports_blend_equation && _glBlendEquation == NULL) {
-    GLCAT.warning()
-      << "BlendEquation advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n";
-  }
+
   if (_glBlendEquation == NULL) {
   if (_glBlendEquation == NULL) {
     _glBlendEquation = null_glBlendEquation;
     _glBlendEquation = null_glBlendEquation;
+    GLCAT.warning()
+      << "BlendEquation advertised as supported by OpenGL runtime, but could "
+         "not get pointer to extension function.\n";
+  }
+
+  if (is_at_least_gl_version(2, 0)) {
+    _supports_blend_equation_separate = true;
+    _glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)
+      get_extension_func("glBlendEquationSeparate");
+
+  } else if (has_extension("GL_EXT_blend_equation_separate")) {
+    _supports_blend_equation_separate = true;
+    _glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEEXTPROC)
+      get_extension_func("glBlendEquationSeparateEXT");
+
+  } else {
+    _supports_blend_equation_separate = false;
+    _glBlendEquationSeparate = NULL;
+  }
+
+  if (_supports_blend_equation_separate && _glBlendEquationSeparate == NULL) {
+    _supports_blend_equation_separate = false;
+    GLCAT.warning()
+      << "BlendEquationSeparate advertised as supported by OpenGL runtime, "
+         "but could not get pointer to extension function.\n";
+  }
+
+  if (is_at_least_gl_version(1, 4)) {
+    _glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)
+      get_extension_func("glBlendFuncSeparate");
+
+  } else if (has_extension("GL_EXT_blend_func_separate")) {
+    _glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEEXTPROC)
+      get_extension_func("glBlendFuncSeparateEXT");
+
+  } else {
+    _glBlendFuncSeparate = null_glBlendFuncSeparate;
+  }
+
+  if (_glBlendFuncSeparate == NULL) {
+    _glBlendFuncSeparate = null_glBlendFuncSeparate;
+    GLCAT.warning()
+      << "BlendFuncSeparate advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n";
   }
   }
 #endif
 #endif
 
 
@@ -2332,6 +2425,15 @@ reset() {
   }
   }
 #endif
 #endif
 
 
+#ifdef OPENGLES_1
+  // OpenGL ES 1 doesn't support dual-source blending.
+#elif defined(OPENGLES)
+  _supports_dual_source_blending = has_extension("GL_EXT_blend_func_extended");
+#else
+  _supports_dual_source_blending =
+    is_at_least_gl_version(3, 3) || has_extension("GL_ARB_blend_func_extended");
+#endif
+
 #ifdef OPENGLES
 #ifdef OPENGLES
   _edge_clamp = GL_CLAMP_TO_EDGE;
   _edge_clamp = GL_CLAMP_TO_EDGE;
 #else
 #else
@@ -6902,6 +7004,7 @@ do_issue_blending() {
   _target_rs->get_attrib_def(target_color_blend);
   _target_rs->get_attrib_def(target_color_blend);
   CPT(ColorBlendAttrib) color_blend = target_color_blend;
   CPT(ColorBlendAttrib) color_blend = target_color_blend;
   ColorBlendAttrib::Mode color_blend_mode = target_color_blend->get_mode();
   ColorBlendAttrib::Mode color_blend_mode = target_color_blend->get_mode();
+  ColorBlendAttrib::Mode alpha_blend_mode = target_color_blend->get_alpha_mode();
 
 
   const TransparencyAttrib *target_transparency;
   const TransparencyAttrib *target_transparency;
   _target_rs->get_attrib_def(target_transparency);
   _target_rs->get_attrib_def(target_transparency);
@@ -6914,9 +7017,17 @@ do_issue_blending() {
     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);
-    _glBlendEquation(get_blend_equation_type(color_blend_mode));
-    glBlendFunc(get_blend_func(color_blend->get_operand_a()),
-                get_blend_func(color_blend->get_operand_b()));
+
+    if (_supports_blend_equation_separate) {
+      _glBlendEquationSeparate(get_blend_equation_type(color_blend_mode),
+                               get_blend_equation_type(alpha_blend_mode));
+    } else {
+      _glBlendEquation(get_blend_equation_type(color_blend_mode));
+    }
+    _glBlendFuncSeparate(get_blend_func(color_blend->get_operand_a()),
+                         get_blend_func(color_blend->get_operand_b()),
+                         get_blend_func(color_blend->get_alpha_operand_a()),
+                         get_blend_func(color_blend->get_alpha_operand_b()));
 
 
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
     LColor c;
     LColor c;
@@ -6931,9 +7042,17 @@ do_issue_blending() {
 #endif
 #endif
 
 
     if (GLCAT.is_spam()) {
     if (GLCAT.is_spam()) {
-      GLCAT.spam() << "glBlendEquation(" << color_blend_mode << ")\n";
-      GLCAT.spam() << "glBlendFunc(" << color_blend->get_operand_a()
-                                     << color_blend->get_operand_b() << ")\n";
+      if (_supports_blend_equation_separate) {
+        GLCAT.spam() << "glBlendEquationSeparate(" << color_blend_mode << ", "
+                                                   << alpha_blend_mode << ")\n";
+      } else {
+        GLCAT.spam() << "glBlendEquation(" << color_blend_mode << ")\n";
+      }
+      GLCAT.spam() << "glBlendFuncSeparate("
+                   << color_blend->get_operand_a() << ", "
+                   << color_blend->get_operand_b() << ", "
+                   << color_blend->get_alpha_operand_a() << ", "
+                   << color_blend->get_alpha_operand_b() << ")\n";
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
       GLCAT.spam() << "glBlendColor(" << c << ")\n";
       GLCAT.spam() << "glBlendColor(" << c << ")\n";
 #endif
 #endif
@@ -9304,6 +9423,13 @@ get_blend_func(ColorBlendAttrib::Operand operand) {
   case ColorBlendAttrib::O_one_minus_constant_alpha:
   case ColorBlendAttrib::O_one_minus_constant_alpha:
   case ColorBlendAttrib::O_one_minus_alpha_scale:
   case ColorBlendAttrib::O_one_minus_alpha_scale:
     break;
     break;
+
+  // No dual-source blending, either.
+  case ColorBlendAttrib::O_incoming1_color:
+  case ColorBlendAttrib::O_one_minus_incoming1_color:
+  case ColorBlendAttrib::O_incoming1_alpha:
+  case ColorBlendAttrib::O_one_minus_incoming1_alpha:
+    break;
 #else
 #else
   case ColorBlendAttrib::O_constant_color:
   case ColorBlendAttrib::O_constant_color:
   case ColorBlendAttrib::O_color_scale:
   case ColorBlendAttrib::O_color_scale:
@@ -9320,6 +9446,18 @@ get_blend_func(ColorBlendAttrib::Operand operand) {
   case ColorBlendAttrib::O_one_minus_constant_alpha:
   case ColorBlendAttrib::O_one_minus_constant_alpha:
   case ColorBlendAttrib::O_one_minus_alpha_scale:
   case ColorBlendAttrib::O_one_minus_alpha_scale:
     return GL_ONE_MINUS_CONSTANT_ALPHA;
     return GL_ONE_MINUS_CONSTANT_ALPHA;
+
+  case ColorBlendAttrib::O_incoming1_color:
+    return GL_SRC1_COLOR;
+
+  case ColorBlendAttrib::O_one_minus_incoming1_color:
+    return GL_ONE_MINUS_SRC1_COLOR;
+
+  case ColorBlendAttrib::O_incoming1_alpha:
+    return GL_SRC1_ALPHA;
+
+  case ColorBlendAttrib::O_one_minus_incoming1_alpha:
+    return GL_ONE_MINUS_SRC1_ALPHA;
 #endif
 #endif
 
 
   case ColorBlendAttrib::O_incoming_color_saturate:
   case ColorBlendAttrib::O_incoming_color_saturate:

+ 6 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -141,6 +141,8 @@ typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, G
 typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array);
 typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array);
 typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
 typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
 typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
 typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
 
 
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
 // GLSL shader functions
 // GLSL shader functions
@@ -817,8 +819,12 @@ public:
   PFNGLBUFFERSTORAGEPROC _glBufferStorage;
   PFNGLBUFFERSTORAGEPROC _glBufferStorage;
 #endif
 #endif
 
 
+  bool _supports_blend_equation_separate;
 #ifndef OPENGLES_2
 #ifndef OPENGLES_2
+  // OpenGL ES 2+ has these in the core.
   PFNGLBLENDEQUATIONPROC _glBlendEquation;
   PFNGLBLENDEQUATIONPROC _glBlendEquation;
+  PFNGLBLENDEQUATIONSEPARATEPROC _glBlendEquationSeparate;
+  PFNGLBLENDFUNCSEPARATEPROC _glBlendFuncSeparate;
 #endif
 #endif
 #ifndef OPENGLES
 #ifndef OPENGLES
   PFNGLBLENDCOLORPROC _glBlendColor;
   PFNGLBLENDCOLORPROC _glBlendColor;

+ 44 - 15
panda/src/pgraph/colorBlendAttrib.I

@@ -19,6 +19,9 @@ ColorBlendAttrib() :
   _mode(M_none),
   _mode(M_none),
   _a(O_one),
   _a(O_one),
   _b(O_one),
   _b(O_one),
+  _alpha_mode(M_none),
+  _alpha_a(O_one),
+  _alpha_b(O_one),
   _color(LColor::zero()),
   _color(LColor::zero()),
   _involves_constant_color(false),
   _involves_constant_color(false),
   _involves_color_scale(false)
   _involves_color_scale(false)
@@ -31,18 +34,29 @@ ColorBlendAttrib() :
 INLINE ColorBlendAttrib::
 INLINE ColorBlendAttrib::
 ColorBlendAttrib(ColorBlendAttrib::Mode mode,
 ColorBlendAttrib(ColorBlendAttrib::Mode mode,
                  ColorBlendAttrib::Operand a, ColorBlendAttrib::Operand b,
                  ColorBlendAttrib::Operand a, ColorBlendAttrib::Operand b,
+                 ColorBlendAttrib::Mode alpha_mode,
+                 ColorBlendAttrib::Operand alpha_a, ColorBlendAttrib::Operand alpha_b,
                  const LColor &color) :
                  const LColor &color) :
   _mode(mode),
   _mode(mode),
   _a(a),
   _a(a),
   _b(b),
   _b(b),
+  _alpha_mode(alpha_mode),
+  _alpha_a(alpha_a),
+  _alpha_b(alpha_b),
   _color(color),
   _color(color),
-  _involves_constant_color(involves_constant_color(a) || involves_constant_color(b)),
-  _involves_color_scale(involves_color_scale(a) || involves_color_scale(b))
+  _involves_constant_color(involves_constant_color(a) ||
+                           involves_constant_color(b) ||
+                           involves_constant_color(alpha_a) ||
+                           involves_constant_color(alpha_b)),
+  _involves_color_scale(involves_color_scale(a) ||
+                        involves_color_scale(b) ||
+                        involves_color_scale(alpha_a) ||
+                        involves_color_scale(alpha_b))
 {
 {
 }
 }
 
 
 /**
 /**
- * Returns the colorBlend mode.
+ * Returns the blending mode for the RGB channels.
  */
  */
 INLINE ColorBlendAttrib::Mode ColorBlendAttrib::
 INLINE ColorBlendAttrib::Mode ColorBlendAttrib::
 get_mode() const {
 get_mode() const {
@@ -50,7 +64,7 @@ get_mode() const {
 }
 }
 
 
 /**
 /**
- * Returns the multiplier for the first component.
+ * Returns the RGB multiplier for the first component.
  */
  */
 INLINE ColorBlendAttrib::Operand ColorBlendAttrib::
 INLINE ColorBlendAttrib::Operand ColorBlendAttrib::
 get_operand_a() const {
 get_operand_a() const {
@@ -58,13 +72,37 @@ get_operand_a() const {
 }
 }
 
 
 /**
 /**
- * Returns the multiplier for the second component.
+ * Returns the RGB multiplier for the second component.
  */
  */
 INLINE ColorBlendAttrib::Operand ColorBlendAttrib::
 INLINE ColorBlendAttrib::Operand ColorBlendAttrib::
 get_operand_b() const {
 get_operand_b() const {
   return _b;
   return _b;
 }
 }
 
 
+/**
+ * Returns the blending mode for the alpha channel.
+ */
+INLINE ColorBlendAttrib::Mode ColorBlendAttrib::
+get_alpha_mode() const {
+  return _alpha_mode;
+}
+
+/**
+ * Returns the alpha multiplier for the first component.
+ */
+INLINE ColorBlendAttrib::Operand ColorBlendAttrib::
+get_alpha_operand_a() const {
+  return _alpha_a;
+}
+
+/**
+ * Returns the alpha multiplier for the second component.
+ */
+INLINE ColorBlendAttrib::Operand ColorBlendAttrib::
+get_alpha_operand_b() const {
+  return _alpha_b;
+}
+
 /**
 /**
  * Returns the constant color associated with the attrib.
  * Returns the constant color associated with the attrib.
  */
  */
@@ -114,14 +152,5 @@ involves_constant_color(ColorBlendAttrib::Operand operand) {
  */
  */
 INLINE bool ColorBlendAttrib::
 INLINE bool ColorBlendAttrib::
 involves_color_scale(ColorBlendAttrib::Operand operand) {
 involves_color_scale(ColorBlendAttrib::Operand operand) {
-  switch (operand) {
-  case O_color_scale:
-  case O_one_minus_color_scale:
-  case O_alpha_scale:
-  case O_one_minus_alpha_scale:
-    return true;
-
-  default:
-    return false;
-  }
+  return (operand >= O_color_scale);
 }
 }

+ 60 - 5
panda/src/pgraph/colorBlendAttrib.cxx

@@ -39,19 +39,38 @@ make_off() {
 CPT(RenderAttrib) ColorBlendAttrib::
 CPT(RenderAttrib) ColorBlendAttrib::
 make(ColorBlendAttrib::Mode mode) {
 make(ColorBlendAttrib::Mode mode) {
   ColorBlendAttrib *attrib = new ColorBlendAttrib(mode, O_one, O_one,
   ColorBlendAttrib *attrib = new ColorBlendAttrib(mode, O_one, O_one,
+                                                  mode, O_one, O_one,
                                                   LColor::zero());
                                                   LColor::zero());
   return return_new(attrib);
   return return_new(attrib);
 }
 }
 
 
 /**
 /**
  * Constructs a new ColorBlendAttrib object that enables special-effect
  * Constructs a new ColorBlendAttrib object that enables special-effect
- * blending.  This supercedes transparency.
+ * blending.  This supercedes transparency.  The given mode and operands are
+ * used for both the RGB and alpha channels.
  */
  */
 CPT(RenderAttrib) ColorBlendAttrib::
 CPT(RenderAttrib) ColorBlendAttrib::
 make(ColorBlendAttrib::Mode mode,
 make(ColorBlendAttrib::Mode mode,
      ColorBlendAttrib::Operand a, ColorBlendAttrib::Operand b,
      ColorBlendAttrib::Operand a, ColorBlendAttrib::Operand b,
      const LColor &color) {
      const LColor &color) {
-  ColorBlendAttrib *attrib = new ColorBlendAttrib(mode, a, b, color);
+  ColorBlendAttrib *attrib = new ColorBlendAttrib(mode, a, b, mode, a, b, color);
+  return return_new(attrib);
+}
+
+/**
+ * Constructs a new ColorBlendAttrib object that enables special-effect
+ * blending.  This supercedes transparency.  This form is used to specify
+ * separate blending parameters for the RGB and alpha channels.
+ */
+CPT(RenderAttrib) ColorBlendAttrib::
+make(ColorBlendAttrib::Mode mode,
+     ColorBlendAttrib::Operand a, ColorBlendAttrib::Operand b,
+     ColorBlendAttrib::Mode alpha_mode,
+     ColorBlendAttrib::Operand alpha_a, ColorBlendAttrib::Operand alpha_b,
+     const LColor &color) {
+  ColorBlendAttrib *attrib = new ColorBlendAttrib(mode, a, b,
+                                                  alpha_mode, alpha_a, alpha_b,
+                                                  color);
   return return_new(attrib);
   return return_new(attrib);
 }
 }
 
 
@@ -187,10 +206,34 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   _mode = (Mode)scan.get_uint8();
   _mode = (Mode)scan.get_uint8();
   _a = (Operand)scan.get_uint8();
   _a = (Operand)scan.get_uint8();
   _b = (Operand)scan.get_uint8();
   _b = (Operand)scan.get_uint8();
+
+  if (manager->get_file_minor_ver() >= 42) {
+    _alpha_mode = (Mode)scan.get_uint8();
+    _alpha_a = (Operand)scan.get_uint8();
+    _alpha_b = (Operand)scan.get_uint8();
+  } else {
+    // Before bam 6.42, these were shifted by four.
+    if (_a >= O_incoming1_color) {
+      _a = (Operand)(_a + 4);
+    }
+    if (_b >= O_incoming1_color) {
+      _b = (Operand)(_b + 4);
+    }
+
+    // And there was only one set of blend constants for both RGB and alpha.
+    _alpha_mode = _mode;
+    _alpha_a = _a;
+    _alpha_b = _b;
+  }
+
   _color.read_datagram(scan);
   _color.read_datagram(scan);
 
 
-  _involves_constant_color = involves_constant_color(_a) || involves_constant_color(_b);
-  _involves_color_scale = involves_color_scale(_a) || involves_color_scale(_b);
+  _involves_constant_color =
+    involves_constant_color(_a) || involves_constant_color(_alpha_a) ||
+    involves_constant_color(_b) || involves_constant_color(_alpha_b);
+  _involves_color_scale =
+    involves_color_scale(_a) || involves_color_scale(_alpha_a) ||
+    involves_color_scale(_b) || involves_color_scale(_alpha_b);
 }
 }
 
 
 /**
 /**
@@ -234,7 +277,7 @@ operator << (ostream &out, ColorBlendAttrib::Operand operand) {
     return out << "one";
     return out << "one";
 
 
   case ColorBlendAttrib::O_incoming_color:
   case ColorBlendAttrib::O_incoming_color:
-    return out << "incomfing_color";
+    return out << "incoming_color";
 
 
   case ColorBlendAttrib::O_one_minus_incoming_color:
   case ColorBlendAttrib::O_one_minus_incoming_color:
     return out << "one_minus_incoming_color";
     return out << "one_minus_incoming_color";
@@ -283,6 +326,18 @@ operator << (ostream &out, ColorBlendAttrib::Operand operand) {
 
 
   case ColorBlendAttrib::O_one_minus_alpha_scale:
   case ColorBlendAttrib::O_one_minus_alpha_scale:
     return out << "one_minus_alpha_scale";
     return out << "one_minus_alpha_scale";
+
+  case ColorBlendAttrib::O_incoming1_color:
+    return out << "incoming1_color";
+
+  case ColorBlendAttrib::O_one_minus_incoming1_color:
+    return out << "one_minus_incoming1_color";
+
+  case ColorBlendAttrib::O_incoming1_alpha:
+    return out << "incoming1_alpha";
+
+  case ColorBlendAttrib::O_one_minus_incoming1_alpha:
+    return out << "one_minus_incoming1_alpha";
   }
   }
 
 
   return out << "**invalid ColorBlendAttrib::Operand(" << (int)operand << ")**";
   return out << "**invalid ColorBlendAttrib::Operand(" << (int)operand << ")**";

+ 25 - 5
panda/src/pgraph/colorBlendAttrib.h

@@ -52,11 +52,20 @@ PUBLISHED:
     O_one_minus_constant_alpha,
     O_one_minus_constant_alpha,
     O_incoming_color_saturate,  // valid only for operand a
     O_incoming_color_saturate,  // valid only for operand a
 
 
-    // If you set either of the operands to any of the below, the blend color
-    // is taken from the current ColorScaleAttrib.  This also inhibits the
-    // normal behavior of the ColorScaleAttrib; it no longer directly scales
-    // the vertex colors, on the assumption that you will instead take care of
-    // the scale here, in the blend mode.
+    // The following are used for dual-source blending, where the fragment
+    // shader outputs a second color that will be used for blending.
+    O_incoming1_color,
+    O_one_minus_incoming1_color,
+    O_incoming1_alpha,
+    O_one_minus_incoming1_alpha,
+
+    // If you set any of the operands to any of the below, the blend color is
+    // taken from the current ColorScaleAttrib.  This also inhibits the normal
+    // behavior of the ColorScaleAttrib; it no longer directly scales the
+    // vertex colors, on the assumption that you will instead take care of the
+    // scale here, in the blend mode.
+    //
+    // These modes are being considered for deprecation.
     O_color_scale,
     O_color_scale,
     O_one_minus_color_scale,
     O_one_minus_color_scale,
     O_alpha_scale,
     O_alpha_scale,
@@ -66,6 +75,7 @@ PUBLISHED:
 private:
 private:
   INLINE ColorBlendAttrib();
   INLINE ColorBlendAttrib();
   INLINE ColorBlendAttrib(Mode mode, Operand a, Operand b,
   INLINE ColorBlendAttrib(Mode mode, Operand a, Operand b,
+                          Mode alpha_mode, Operand alpha_a, Operand alpha_b,
                           const LColor &color);
                           const LColor &color);
 
 
 PUBLISHED:
 PUBLISHED:
@@ -73,11 +83,19 @@ PUBLISHED:
   static CPT(RenderAttrib) make(Mode mode);
   static CPT(RenderAttrib) make(Mode mode);
   static CPT(RenderAttrib) make(Mode mode, Operand a, Operand b,
   static CPT(RenderAttrib) make(Mode mode, Operand a, Operand b,
                                 const LColor &color = LColor::zero());
                                 const LColor &color = LColor::zero());
+  static CPT(RenderAttrib) make(Mode rgb_mode, Operand rgb_a, Operand rgb_b,
+                                Mode alpha_mode, Operand alpha_a, Operand alpha_b,
+                                const LColor &color = LColor::zero());
   static CPT(RenderAttrib) make_default();
   static CPT(RenderAttrib) make_default();
 
 
   INLINE Mode get_mode() const;
   INLINE Mode get_mode() const;
   INLINE Operand get_operand_a() const;
   INLINE Operand get_operand_a() const;
   INLINE Operand get_operand_b() const;
   INLINE Operand get_operand_b() const;
+
+  INLINE Mode get_alpha_mode() const;
+  INLINE Operand get_alpha_operand_a() const;
+  INLINE Operand get_alpha_operand_b() const;
+
   INLINE LColor get_color() const;
   INLINE LColor get_color() const;
 
 
   INLINE bool involves_constant_color() const;
   INLINE bool involves_constant_color() const;
@@ -97,6 +115,8 @@ protected:
 private:
 private:
   Mode _mode;
   Mode _mode;
   Operand _a, _b;
   Operand _a, _b;
+  Mode _alpha_mode;
+  Operand _alpha_a, _alpha_b;
   LColor _color;
   LColor _color;
   bool _involves_constant_color;
   bool _involves_constant_color;
   bool _involves_color_scale;
   bool _involves_color_scale;

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

@@ -32,7 +32,7 @@ static const unsigned short _bam_major_ver = 6;
 // Bumped to major version 6 on 2006-02-11 to factor out PandaNode::CData.
 // Bumped to major version 6 on 2006-02-11 to factor out PandaNode::CData.
 
 
 static const unsigned short _bam_first_minor_ver = 14;
 static const unsigned short _bam_first_minor_ver = 14;
-static const unsigned short _bam_minor_ver = 41;
+static const unsigned short _bam_minor_ver = 42;
 // Bumped to minor version 14 on 2007-12-19 to change default ColorAttrib.
 // Bumped to minor version 14 on 2007-12-19 to change default ColorAttrib.
 // Bumped to minor version 15 on 2008-04-09 to add TextureAttrib::_implicit_sort.
 // Bumped to minor version 15 on 2008-04-09 to add TextureAttrib::_implicit_sort.
 // Bumped to minor version 16 on 2008-05-13 to add Texture::_quality_level.
 // Bumped to minor version 16 on 2008-05-13 to add Texture::_quality_level.
@@ -61,5 +61,6 @@ static const unsigned short _bam_minor_ver = 41;
 // Bumped to minor version 39 on 2016-01-09 to change lights and materials.
 // Bumped to minor version 39 on 2016-01-09 to change lights and materials.
 // Bumped to minor version 40 on 2016-01-11 to make NodePaths writable.
 // Bumped to minor version 40 on 2016-01-11 to make NodePaths writable.
 // Bumped to minor version 41 on 2016-03-02 to change LensNode, Lens, and Camera.
 // Bumped to minor version 41 on 2016-03-02 to change LensNode, Lens, and Camera.
+// Bumped to minor version 42 on 2016-04-08 to expand ColorBlendAttrib.
 
 
 #endif
 #endif