Browse Source

extend ColorBlendAttrib

David Rose 21 years ago
parent
commit
a25c6928d0

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

@@ -814,6 +814,7 @@ issue_transparency(const TransparencyAttrib *attrib) {
 ////////////////////////////////////////////////////////////////////
 void GraphicsStateGuardian::
 issue_color_blend(const ColorBlendAttrib *attrib) {
+  _color_blend = attrib;
   _color_blend_mode = attrib->get_mode();
   set_blend_mode(_color_write_mode, _color_blend_mode, _transparency_mode);
 }

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

@@ -269,6 +269,7 @@ protected:
   ColorWriteAttrib::Mode _color_write_mode;
   ColorBlendAttrib::Mode _color_blend_mode;
   TransparencyAttrib::Mode _transparency_mode;
+  CPT(ColorBlendAttrib) _color_blend;
 
   bool _needs_reset;
   bool _closing_gsg;

+ 72 - 21
panda/src/dxgsg7/dxGraphicsStateGuardian7.cxx

@@ -894,6 +894,70 @@ void INLINE TestDrawPrimFailure(DP_Type dptype,HRESULT hr,LPDIRECTDRAW7 pDD,DWOR
 #define TestDrawPrimFailure(a,b,c,nVerts,nTris) CountDPs(nVerts,nTris);
 #endif
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXGraphicsStateGuardian7::get_blend_func
+//       Access: Protected, Static
+//  Description: Maps from ColorBlendAttrib::Operand to D3DBLEND
+//               value.
+////////////////////////////////////////////////////////////////////
+D3DBLEND DXGraphicsStateGuardian7::
+get_blend_func(ColorBlendAttrib::Operand operand) {
+  switch (operand) {
+  case ColorBlendAttrib::O_zero:
+    return D3DBLEND_ZERO;
+
+  case ColorBlendAttrib::O_one:
+    return D3DBLEND_ONE;
+
+  case ColorBlendAttrib::O_incoming_color:
+    return D3DBLEND_SRCCOLOR;
+
+  case ColorBlendAttrib::O_one_minus_incoming_color:
+    return D3DBLEND_INVSRCCOLOR;
+
+  case ColorBlendAttrib::O_fbuffer_color:
+    return D3DBLEND_DESTCOLOR;
+
+  case ColorBlendAttrib::O_one_minus_fbuffer_color:
+    return D3DBLEND_INVDESTCOLOR;
+
+  case ColorBlendAttrib::O_incoming_alpha:
+    return D3DBLEND_SRCALPHA;
+
+  case ColorBlendAttrib::O_one_minus_incoming_alpha:
+    return D3DBLEND_INVSRCALPHA;
+
+  case ColorBlendAttrib::O_fbuffer_alpha:
+    return D3DBLEND_DESTALPHA;
+
+  case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
+    return D3DBLEND_INVDESTALPHA;
+
+  case ColorBlendAttrib::O_constant_color:
+    // Not supported by DX.
+    return D3DBLEND_SRCCOLOR;
+
+  case ColorBlendAttrib::O_one_minus_constant_color:
+    // Not supported by DX.
+    return D3DBLEND_INVSRCCOLOR;
+
+  case ColorBlendAttrib::O_constant_alpha:
+    // Not supported by DX.
+    return D3DBLEND_SRCALPHA;
+
+  case ColorBlendAttrib::O_one_minus_constant_alpha:
+    // Not supported by DX.
+    return D3DBLEND_INVSRCALPHA;
+
+  case ColorBlendAttrib::O_incoming_color_saturate:
+    return D3DBLEND_SRCALPHASAT;
+  }
+
+  dxgsg7_cat.error()
+    << "Unknown color blend operand " << (int)operand << endl;
+  return D3DBLEND_ZERO;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian7::report_texmgr_stats
 //       Access: Protected
@@ -4536,31 +4600,18 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
     call_dxBlendFunc(D3DBLEND_ZERO, D3DBLEND_ONE);
     return;
   }
-
+  
   // Is there a color blend set?
-  switch (color_blend_mode) {
-  case ColorBlendAttrib::M_none:
-    break;
-
-  case ColorBlendAttrib::M_multiply:
+  if (color_blend_mode != ColorBlendAttrib::M_none) {
     enable_blend(true);
-    call_dxBlendFunc(D3DBLEND_DESTCOLOR, D3DBLEND_ZERO);
-    return;
 
-  case ColorBlendAttrib::M_add:
-    enable_blend(true);
-    call_dxBlendFunc(D3DBLEND_ONE, D3DBLEND_ONE);
-    return;
-
-  case ColorBlendAttrib::M_multiply_add:
-    enable_blend(true);
-    call_dxBlendFunc(D3DBLEND_DESTCOLOR, D3DBLEND_ONE);
+    // DX7 supports only ColorBlendAttrib::M_add.  Assume that's what
+    // we've got; if the user asked for anything else, give him M_add
+    // instead.
+  
+    call_dxBlendFunc(get_blend_func(_color_blend->get_operand_a()),
+                     get_blend_func(_color_blend->get_operand_b()));
     return;
-
-  default:
-    dxgsg7_cat.error()
-      << "Unknown color blend mode " << (int)color_blend_mode << endl;
-    break;
   }
 
   // No color blend; is there a transparency set?

+ 1 - 0
panda/src/dxgsg7/dxGraphicsStateGuardian7.h

@@ -217,6 +217,7 @@ protected:
   INLINE void call_dxLightModelAmbient(const Colorf& color);
   INLINE void call_dxAlphaFunc(D3DCMPFUNC func, float ref);
   INLINE void call_dxBlendFunc(D3DBLEND sfunc, D3DBLEND dfunc);
+  static D3DBLEND get_blend_func(ColorBlendAttrib::Operand operand);
   INLINE void enable_dither(bool val);
   INLINE void enable_stencil_test(bool val);
   void report_texmgr_stats();

+ 89 - 19
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -1092,6 +1092,70 @@ void DXGraphicsStateGuardian8::set_clipper(RECT cliprect) {
 }
 #endif
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXGraphicsStateGuardian8::get_blend_func
+//       Access: Protected, Static
+//  Description: Maps from ColorBlendAttrib::Operand to D3DBLEND
+//               value.
+////////////////////////////////////////////////////////////////////
+D3DBLEND DXGraphicsStateGuardian8::
+get_blend_func(ColorBlendAttrib::Operand operand) {
+  switch (operand) {
+  case ColorBlendAttrib::O_zero:
+    return D3DBLEND_ZERO;
+
+  case ColorBlendAttrib::O_one:
+    return D3DBLEND_ONE;
+
+  case ColorBlendAttrib::O_incoming_color:
+    return D3DBLEND_SRCCOLOR;
+
+  case ColorBlendAttrib::O_one_minus_incoming_color:
+    return D3DBLEND_INVSRCCOLOR;
+
+  case ColorBlendAttrib::O_fbuffer_color:
+    return D3DBLEND_DESTCOLOR;
+
+  case ColorBlendAttrib::O_one_minus_fbuffer_color:
+    return D3DBLEND_INVDESTCOLOR;
+
+  case ColorBlendAttrib::O_incoming_alpha:
+    return D3DBLEND_SRCALPHA;
+
+  case ColorBlendAttrib::O_one_minus_incoming_alpha:
+    return D3DBLEND_INVSRCALPHA;
+
+  case ColorBlendAttrib::O_fbuffer_alpha:
+    return D3DBLEND_DESTALPHA;
+
+  case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
+    return D3DBLEND_INVDESTALPHA;
+
+  case ColorBlendAttrib::O_constant_color:
+    // Not supported by DX.
+    return D3DBLEND_SRCCOLOR;
+
+  case ColorBlendAttrib::O_one_minus_constant_color:
+    // Not supported by DX.
+    return D3DBLEND_INVSRCCOLOR;
+
+  case ColorBlendAttrib::O_constant_alpha:
+    // Not supported by DX.
+    return D3DBLEND_SRCALPHA;
+
+  case ColorBlendAttrib::O_one_minus_constant_alpha:
+    // Not supported by DX.
+    return D3DBLEND_INVSRCALPHA;
+
+  case ColorBlendAttrib::O_incoming_color_saturate:
+    return D3DBLEND_SRCALPHASAT;
+  }
+
+  dxgsg8_cat.error()
+    << "Unknown color blend operand " << (int)operand << endl;
+  return D3DBLEND_ZERO;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian8::report_texmgr_stats
 //       Access: Protected
@@ -4241,29 +4305,34 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
   }
 
   // Is there a color blend set?
-  switch (color_blend_mode) {
-  case ColorBlendAttrib::M_none:
-    break;
-
-  case ColorBlendAttrib::M_multiply:
+  if (color_blend_mode != ColorBlendAttrib::M_none) {
     enable_blend(true);
-    call_dxBlendFunc(D3DBLEND_DESTCOLOR, D3DBLEND_ZERO);
-    return;
+  
+    switch (color_blend_mode) {
+    case ColorBlendAttrib::M_add:
+      _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
+      break;
 
-  case ColorBlendAttrib::M_add:
-    enable_blend(true);
-    call_dxBlendFunc(D3DBLEND_ONE, D3DBLEND_ONE);
-    return;
+    case ColorBlendAttrib::M_subtract:
+      _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
+      break;
 
-  case ColorBlendAttrib::M_multiply_add:
-    enable_blend(true);
-    call_dxBlendFunc(D3DBLEND_DESTCOLOR, D3DBLEND_ONE);
-    return;
+    case ColorBlendAttrib::M_inv_subtract:
+      _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT);
+      break;
 
-  default:
-    dxgsg8_cat.error()
-      << "Unknown color blend mode " << (int)color_blend_mode << endl;
-    break;
+    case ColorBlendAttrib::M_min:
+      _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_MIN);
+      break;
+
+    case ColorBlendAttrib::M_max:
+      _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_MAX);
+      break;
+    }
+  
+    call_dxBlendFunc(get_blend_func(_color_blend->get_operand_a()),
+                     get_blend_func(_color_blend->get_operand_b()));
+    return;
   }
 
   // No color blend; is there a transparency set?
@@ -4278,6 +4347,7 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
   case TransparencyAttrib::M_multisample_mask:
   case TransparencyAttrib::M_dual:
     enable_blend(true);
+    _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
     call_dxBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
     return;
 

+ 1 - 0
panda/src/dxgsg8/dxGraphicsStateGuardian8.h

@@ -217,6 +217,7 @@ protected:
   INLINE void call_dxLightModelAmbient(const Colorf& color);
   INLINE void call_dxAlphaFunc(D3DCMPFUNC func, float refval);
   INLINE void call_dxBlendFunc(D3DBLEND sfunc, D3DBLEND dfunc);
+  static D3DBLEND get_blend_func(ColorBlendAttrib::Operand operand);
   INLINE void enable_dither(bool val);
   INLINE void enable_stencil_test(bool val);
   void report_texmgr_stats();

+ 90 - 20
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -769,7 +769,6 @@ dx_init(void) {
     _alpha_test_enabled = false;
     _pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, _alpha_test_enabled);
 
-    // this is a new DX9 state that lets you do additional operations other than ADD (e.g. subtract/max/min)
     // must check (_pScrn->d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_BLENDOP) (yes on GF2/Radeon8500, no on TNT)
     _pD3DDevice->SetRenderState(D3DRS_BLENDOP,D3DBLENDOP_ADD);
 
@@ -1085,6 +1084,70 @@ void DXGraphicsStateGuardian9::set_clipper(RECT cliprect) {
 }
 #endif
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXGraphicsStateGuardian9::get_blend_func
+//       Access: Protected, Static
+//  Description: Maps from ColorBlendAttrib::Operand to D3DBLEND
+//               value.
+////////////////////////////////////////////////////////////////////
+D3DBLEND DXGraphicsStateGuardian9::
+get_blend_func(ColorBlendAttrib::Operand operand) {
+  switch (operand) {
+  case ColorBlendAttrib::O_zero:
+    return D3DBLEND_ZERO;
+
+  case ColorBlendAttrib::O_one:
+    return D3DBLEND_ONE;
+
+  case ColorBlendAttrib::O_incoming_color:
+    return D3DBLEND_SRCCOLOR;
+
+  case ColorBlendAttrib::O_one_minus_incoming_color:
+    return D3DBLEND_INVSRCCOLOR;
+
+  case ColorBlendAttrib::O_fbuffer_color:
+    return D3DBLEND_DESTCOLOR;
+
+  case ColorBlendAttrib::O_one_minus_fbuffer_color:
+    return D3DBLEND_INVDESTCOLOR;
+
+  case ColorBlendAttrib::O_incoming_alpha:
+    return D3DBLEND_SRCALPHA;
+
+  case ColorBlendAttrib::O_one_minus_incoming_alpha:
+    return D3DBLEND_INVSRCALPHA;
+
+  case ColorBlendAttrib::O_fbuffer_alpha:
+    return D3DBLEND_DESTALPHA;
+
+  case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
+    return D3DBLEND_INVDESTALPHA;
+
+  case ColorBlendAttrib::O_constant_color:
+    // Not supported by DX.
+    return D3DBLEND_SRCCOLOR;
+
+  case ColorBlendAttrib::O_one_minus_constant_color:
+    // Not supported by DX.
+    return D3DBLEND_INVSRCCOLOR;
+
+  case ColorBlendAttrib::O_constant_alpha:
+    // Not supported by DX.
+    return D3DBLEND_SRCALPHA;
+
+  case ColorBlendAttrib::O_one_minus_constant_alpha:
+    // Not supported by DX.
+    return D3DBLEND_INVSRCALPHA;
+
+  case ColorBlendAttrib::O_incoming_color_saturate:
+    return D3DBLEND_SRCALPHASAT;
+  }
+
+  dxgsg9_cat.error()
+    << "Unknown color blend operand " << (int)operand << endl;
+  return D3DBLEND_ZERO;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian9::report_texmgr_stats
 //       Access: Protected
@@ -4239,34 +4302,40 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
     // will come this way, and they should ignore the colorwriteattrib value since it's been
     // handled separately in set_color_writemask
     enable_blend(true);
+    _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
     call_dxBlendFunc(D3DBLEND_ZERO, D3DBLEND_ONE);
     return;
   }
 
   // Is there a color blend set?
-  switch (color_blend_mode) {
-  case ColorBlendAttrib::M_none:
-    break;
-
-  case ColorBlendAttrib::M_multiply:
+  if (color_blend_mode != ColorBlendAttrib::M_none) {
     enable_blend(true);
-    call_dxBlendFunc(D3DBLEND_DESTCOLOR, D3DBLEND_ZERO);
-    return;
 
-  case ColorBlendAttrib::M_add:
-    enable_blend(true);
-    call_dxBlendFunc(D3DBLEND_ONE, D3DBLEND_ONE);
-    return;
+    switch (color_blend_mode) {
+    case ColorBlendAttrib::M_add:
+      _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
+      break;
 
-  case ColorBlendAttrib::M_multiply_add:
-    enable_blend(true);
-    call_dxBlendFunc(D3DBLEND_DESTCOLOR, D3DBLEND_ONE);
-    return;
+    case ColorBlendAttrib::M_subtract:
+      _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
+      break;
 
-  default:
-    dxgsg9_cat.error()
-      << "Unknown color blend mode " << (int)color_blend_mode << endl;
-    break;
+    case ColorBlendAttrib::M_inv_subtract:
+      _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT);
+      break;
+
+    case ColorBlendAttrib::M_min:
+      _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_MIN);
+      break;
+
+    case ColorBlendAttrib::M_max:
+      _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_MAX);
+      break;
+    }
+
+    call_dxBlendFunc(get_blend_func(_color_blend->get_operand_a()),
+                     get_blend_func(_color_blend->get_operand_b()));
+    return;
   }
 
   // No color blend; is there a transparency set?
@@ -4281,6 +4350,7 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
   case TransparencyAttrib::M_multisample_mask:
   case TransparencyAttrib::M_dual:
     enable_blend(true);
+    _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
     call_dxBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
     return;
 

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

@@ -218,6 +218,7 @@ protected:
   INLINE void call_dxLightModelAmbient(const Colorf& color);
   INLINE void call_dxAlphaFunc(D3DCMPFUNC func, float refval);
   INLINE void call_dxBlendFunc(D3DBLEND sfunc, D3DBLEND dfunc);
+  static D3DBLEND get_blend_func(ColorBlendAttrib::Operand operand);
   INLINE void enable_dither(bool val);
   INLINE void enable_stencil_test(bool val);
   void report_texmgr_stats();

+ 184 - 74
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -119,9 +119,11 @@ issue_transformed_color_gl(const Geom *geom, Geom::ColorIterator &citerator,
   glgsg->issue_transformed_color(color);
 }
 
-// This noop function is assigned to _glActiveTexture in case we don't
-// have multitexturing support, so it will always be safe to call
-// _glActiveTexture().
+// The following noop functions are assigned to the corresponding
+// glext function pointers in the class, in case the functions are not
+// defined by the GL, just so it will always be safe to call the
+// extension functions.
+
 static void APIENTRY
 null_glActiveTexture(GLenum gl_texture_stage) {
   // If we don't support multitexture, we'd better not try to request
@@ -129,6 +131,14 @@ null_glActiveTexture(GLenum gl_texture_stage) {
   nassertv(gl_texture_stage == GL_TEXTURE0);
 }
 
+static void APIENTRY
+null_glBlendEquation(GLenum) {
+}
+
+static void APIENTRY
+null_glBlendColor(GLclampf, GLclampf, GLclampf, GLclampf) {
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: uchar_bgr_to_rgb
 //  Description: Recopies the given array of pixels, converting from
@@ -335,6 +345,32 @@ reset() {
     _glActiveTexture = null_glActiveTexture;
   }
 
+  _glBlendEquation = NULL;
+  if (has_extension("GL_EXT_blend_minmax") || is_at_least_version(1, 2)) {
+    _glBlendEquation = (PFNGLBLENDEQUATIONEXTPROC)
+      get_extension_func(GLPREFIX_QUOTED, "BlendEquationEXT");
+    if (_glBlendEquation == NULL) {
+      GLCAT.warning()
+        << "BlendEquation advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n";
+    }
+  }
+  if (_glBlendEquation == NULL) {
+    _glBlendEquation = null_glBlendEquation;
+  }
+
+  _glBlendColor = NULL;
+  if (has_extension("GL_EXT_blend_color") || is_at_least_version(1, 2)) {
+    _glBlendColor = (PFNGLBLENDCOLOREXTPROC)
+      get_extension_func(GLPREFIX_QUOTED, "BlendColorEXT");
+    if (_glBlendColor == NULL) {
+      GLCAT.warning()
+        << "BlendColor advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n";
+    }
+  }
+  if (_glBlendColor == NULL) {
+    _glBlendColor = null_glBlendColor;
+  }
+
   _edge_clamp = GL_CLAMP;
   if (has_extension("GL_SGIS_texture_edge_clamp") ||
       is_at_least_version(1, 2)) {
@@ -3440,7 +3476,7 @@ draw_texture(TextureContext *tc, const DisplayRegion *dr) {
       ColorWriteAttrib::make(ColorWriteAttrib::M_on),
       RenderModeAttrib::make(RenderModeAttrib::M_filled),
       //TexMatrixAttrib::make(LMatrix4f::ident_mat()),
-      ColorBlendAttrib::make(ColorBlendAttrib::M_none),
+      ColorBlendAttrib::make_off(),
       TransparencyAttrib::make(TransparencyAttrib::M_none),
     };
     basic_state = 
@@ -3641,7 +3677,7 @@ draw_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
 //               GL's.
 ////////////////////////////////////////////////////////////////////
 GLenum CLP(GraphicsStateGuardian)::
-get_texture_wrap_mode(Texture::WrapMode wm) {
+get_texture_wrap_mode(Texture::WrapMode wm) const {
   if (CLP(ignore_clamp)) {
     return GL_REPEAT;
   }
@@ -3670,7 +3706,7 @@ get_texture_wrap_mode(Texture::WrapMode wm) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::get_texture_filter_type
-//       Access: Protected
+//       Access: Protected, Static
 //  Description: Maps from the Texture's internal filter type symbols
 //               to GL's.
 ////////////////////////////////////////////////////////////////////
@@ -3717,7 +3753,7 @@ get_texture_filter_type(Texture::FilterType ft) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::get_image_type
-//       Access: Protected
+//       Access: Protected, Static
 //  Description: Maps from the PixelBuffer's internal Type symbols
 //               to GL's.
 ////////////////////////////////////////////////////////////////////
@@ -3746,7 +3782,7 @@ get_image_type(PixelBuffer::Type type) {
 //               to GL's.
 ////////////////////////////////////////////////////////////////////
 GLint CLP(GraphicsStateGuardian)::
-get_external_image_format(PixelBuffer::Format format) {
+get_external_image_format(PixelBuffer::Format format) const {
   switch (format) {
   case PixelBuffer::F_color_index:
     return GL_COLOR_INDEX;
@@ -3789,7 +3825,7 @@ get_external_image_format(PixelBuffer::Format format) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::get_internal_image_format
-//       Access: Protected
+//       Access: Protected, Static
 //  Description: Maps from the PixelBuffer's Format symbols to a
 //               suitable internal format for GL textures.
 ////////////////////////////////////////////////////////////////////
@@ -3841,12 +3877,12 @@ get_internal_image_format(PixelBuffer::Format format) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::get_texture_apply_mode_type
-//       Access: Protected
+//       Access: Protected, Static
 //  Description: Maps from the texture stage's mode types
 //               to the corresponding OpenGL ids
 ////////////////////////////////////////////////////////////////////
 GLint CLP(GraphicsStateGuardian)::
-get_texture_apply_mode_type(TextureStage::Mode am) const {
+get_texture_apply_mode_type(TextureStage::Mode am) {
   switch (am) {
   case TextureStage::M_modulate: return GL_MODULATE;
   case TextureStage::M_decal: return GL_DECAL;
@@ -3863,12 +3899,12 @@ get_texture_apply_mode_type(TextureStage::Mode am) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::get_texture_combine_type
-//       Access: Protected
+//       Access: Protected, Static
 //  Description: Maps from the texture stage's CombineMode types
 //               to the corresponding OpenGL ids
 ////////////////////////////////////////////////////////////////////
 GLint CLP(GraphicsStateGuardian)::
-get_texture_combine_type(TextureStage::CombineMode cm) const {
+get_texture_combine_type(TextureStage::CombineMode cm) {
   switch (cm) {
   case TextureStage::CM_undefined: // fall through
   case TextureStage::CM_replace: return GL_REPLACE;
@@ -3887,12 +3923,12 @@ get_texture_combine_type(TextureStage::CombineMode cm) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::get_texture_src_type
-//       Access: Protected
+//       Access: Protected, Static
 //  Description: Maps from the texture stage's CombineSource types
 //               to the corresponding OpenGL ids
 ////////////////////////////////////////////////////////////////////
 GLint CLP(GraphicsStateGuardian)::
-get_texture_src_type(TextureStage::CombineSource cs) const {
+get_texture_src_type(TextureStage::CombineSource cs) {
   switch (cs) {
   case TextureStage::CS_undefined: // fall through
   case TextureStage::CS_texture: return GL_TEXTURE;
@@ -3908,12 +3944,12 @@ get_texture_src_type(TextureStage::CombineSource cs) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::get_texture_operand_type
-//       Access: Protected
+//       Access: Protected, Static
 //  Description: Maps from the texture stage's CombineOperand types
 //               to the corresponding OpenGL ids
 ////////////////////////////////////////////////////////////////////
 GLint CLP(GraphicsStateGuardian)::
-get_texture_operand_type(TextureStage::CombineOperand co) const {
+get_texture_operand_type(TextureStage::CombineOperand co) {
   switch (co) {
   case TextureStage::CO_undefined: // fall through
   case TextureStage::CO_src_alpha: return GL_SRC_ALPHA;
@@ -3929,11 +3965,11 @@ get_texture_operand_type(TextureStage::CombineOperand co) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::get_fog_mode_type
-//       Access: Protected
+//       Access: Protected, Static
 //  Description: Maps from the fog types to gl version
 ////////////////////////////////////////////////////////////////////
 GLenum CLP(GraphicsStateGuardian)::
-get_fog_mode_type(Fog::Mode m) const {
+get_fog_mode_type(Fog::Mode m) {
   switch(m) {
   case Fog::M_linear: return GL_LINEAR;
   case Fog::M_exponential: return GL_EXP;
@@ -3948,6 +3984,97 @@ get_fog_mode_type(Fog::Mode m) const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::get_blend_equation_type
+//       Access: Protected, Static
+//  Description: Maps from ColorBlendAttrib::Mode to glBlendEquation
+//               value.
+////////////////////////////////////////////////////////////////////
+GLenum CLP(GraphicsStateGuardian)::
+get_blend_equation_type(ColorBlendAttrib::Mode mode) {
+  switch (mode) {
+  case ColorBlendAttrib::M_add:
+    return GL_FUNC_ADD;
+    
+  case ColorBlendAttrib::M_subtract:
+    return GL_FUNC_SUBTRACT;
+    
+  case ColorBlendAttrib::M_inv_subtract:
+    return GL_FUNC_REVERSE_SUBTRACT;
+    
+  case ColorBlendAttrib::M_min:
+    return GL_MIN;
+    
+  case ColorBlendAttrib::M_max:
+    return GL_MAX;
+  }    
+
+  GLCAT.error()
+    << "Unknown color blend mode " << (int)mode << endl;
+  return GL_FUNC_ADD;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::get_blend_func
+//       Access: Protected, Static
+//  Description: Maps from ColorBlendAttrib::Operand to glBlendFunc
+//               value.
+////////////////////////////////////////////////////////////////////
+GLenum CLP(GraphicsStateGuardian)::
+get_blend_func(ColorBlendAttrib::Operand operand) {
+  switch (operand) {
+  case ColorBlendAttrib::O_zero:
+    return GL_ZERO;
+
+  case ColorBlendAttrib::O_one:
+    return GL_ONE;
+
+  case ColorBlendAttrib::O_incoming_color:
+    return GL_SRC_COLOR;
+
+  case ColorBlendAttrib::O_one_minus_incoming_color:
+    return GL_ONE_MINUS_SRC_COLOR;
+
+  case ColorBlendAttrib::O_fbuffer_color:
+    return GL_DST_COLOR;
+
+  case ColorBlendAttrib::O_one_minus_fbuffer_color:
+    return GL_ONE_MINUS_DST_COLOR;
+
+  case ColorBlendAttrib::O_incoming_alpha:
+    return GL_SRC_ALPHA;
+
+  case ColorBlendAttrib::O_one_minus_incoming_alpha:
+    return GL_ONE_MINUS_SRC_ALPHA;
+
+  case ColorBlendAttrib::O_fbuffer_alpha:
+    return GL_DST_ALPHA;
+
+  case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
+    return GL_ONE_MINUS_DST_ALPHA;
+
+  case ColorBlendAttrib::O_constant_color:
+    return GL_CONSTANT_COLOR;
+
+  case ColorBlendAttrib::O_one_minus_constant_color:
+    return GL_ONE_MINUS_CONSTANT_COLOR;
+
+  case ColorBlendAttrib::O_constant_alpha:
+    return GL_CONSTANT_ALPHA;
+
+  case ColorBlendAttrib::O_one_minus_constant_alpha:
+    return GL_ONE_MINUS_CONSTANT_ALPHA;
+
+  case ColorBlendAttrib::O_incoming_color_saturate:
+    return GL_SRC_ALPHA_SATURATE;
+  }
+
+  GLCAT.error()
+    << "Unknown color blend operand " << (int)operand << endl;
+  return GL_ZERO;
+}
+
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::print_gfx_visual
 //       Access: Public
@@ -4237,82 +4364,65 @@ set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
     enable_multisample_alpha_one(false);
     enable_multisample_alpha_mask(false);
     enable_blend(true);
+    _glBlendEquation(GL_FUNC_ADD);
     GLP(BlendFunc)(GL_ZERO, GL_ONE);
     return;
   }
 
   // Is there a color blend set?
-  switch (color_blend_mode) {
-  case ColorBlendAttrib::M_none:
-    break;
-
-  case ColorBlendAttrib::M_multiply:
+  if (color_blend_mode != ColorBlendAttrib::M_none) {
     enable_multisample_alpha_one(false);
     enable_multisample_alpha_mask(false);
     enable_blend(true);
-    GLP(BlendFunc)(GL_DST_COLOR, GL_ZERO);
+    _glBlendEquation(get_blend_equation_type(color_blend_mode));
+    GLP(BlendFunc)(get_blend_func(_color_blend->get_operand_a()),
+                   get_blend_func(_color_blend->get_operand_b()));
+    Colorf c = _color_blend->get_color();
+    _glBlendColor(c[0], c[1], c[2], c[3]);
     return;
+  }
 
-  case ColorBlendAttrib::M_add:
+  // No color blend; is there a transparency set?
+  switch (transparency_mode) {
+  case TransparencyAttrib::M_none:
+  case TransparencyAttrib::M_binary:
+    break;
+    
+  case TransparencyAttrib::M_alpha:
+  case TransparencyAttrib::M_alpha_sorted:
+  case TransparencyAttrib::M_dual:
+    // Should we really have an "alpha" and an "alpha_sorted"
+    // mode, like Performer does?  (The difference is that
+    // "alpha_sorted" is with the write to the depth buffer
+    // disabled.)  Or should we just use the separate depth write
+    // transition to control this?  Doing it implicitly requires a
+    // bit more logic here and in the state management; for now we
+    // require the user to explicitly turn off the depth write.
     enable_multisample_alpha_one(false);
     enable_multisample_alpha_mask(false);
     enable_blend(true);
-    GLP(BlendFunc)(GL_ONE, GL_ONE);
+    _glBlendEquation(GL_FUNC_ADD);
+    GLP(BlendFunc)(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     return;
-
-  case ColorBlendAttrib::M_multiply_add:
+    
+  case TransparencyAttrib::M_multisample:
+    enable_multisample_alpha_one(true);
+    enable_multisample_alpha_mask(true);
+    enable_blend(false);
+    return;
+    
+  case TransparencyAttrib::M_multisample_mask:
     enable_multisample_alpha_one(false);
-    enable_multisample_alpha_mask(false);
-    enable_blend(true);
-    GLP(BlendFunc)(GL_DST_COLOR, GL_ONE);
+    enable_multisample_alpha_mask(true);
+    enable_blend(false);
     return;
-
+    
   default:
     GLCAT.error()
-      << "Unknown color blend mode " << (int)color_blend_mode << endl;
+      << "invalid transparency mode " << (int)transparency_mode << endl;
     break;
   }
 
-  // No color blend; is there a transparency set?
-  switch (transparency_mode) {
-      case TransparencyAttrib::M_none:
-      case TransparencyAttrib::M_binary:
-        break;
-    
-      case TransparencyAttrib::M_alpha:
-      case TransparencyAttrib::M_alpha_sorted:
-      case TransparencyAttrib::M_dual:
-        // Should we really have an "alpha" and an "alpha_sorted"
-        // mode, like Performer does?  (The difference is that
-        // "alpha_sorted" is with the write to the depth buffer
-        // disabled.)  Or should we just use the separate depth write
-        // transition to control this?  Doing it implicitly requires a
-        // bit more logic here and in the state management; for now we
-        // require the user to explicitly turn off the depth write.
-        enable_multisample_alpha_one(false);
-        enable_multisample_alpha_mask(false);
-        enable_blend(true);
-        GLP(BlendFunc)(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-        return;
-    
-      case TransparencyAttrib::M_multisample:
-        enable_multisample_alpha_one(true);
-        enable_multisample_alpha_mask(true);
-        enable_blend(false);
-        return;
-    
-      case TransparencyAttrib::M_multisample_mask:
-        enable_multisample_alpha_one(false);
-        enable_multisample_alpha_mask(true);
-        enable_blend(false);
-        return;
-    
-      default:
-        GLCAT.error()
-          << "invalid transparency mode " << (int)transparency_mode << endl;
-        break;
-  }
-
   // Nothing's set, so disable blending.
   enable_multisample_alpha_one(false);
   enable_multisample_alpha_mask(false);

+ 15 - 10
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -206,16 +206,18 @@ protected:
   void draw_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
                          const RenderBuffer &rb);
 
-  GLenum get_texture_wrap_mode(Texture::WrapMode wm);
-  GLenum get_texture_filter_type(Texture::FilterType ft);
-  GLenum get_image_type(PixelBuffer::Type type);
-  GLint get_external_image_format(PixelBuffer::Format format);
-  GLint get_internal_image_format(PixelBuffer::Format format);
-  GLint get_texture_apply_mode_type(TextureStage::Mode am) const;
-  GLint get_texture_combine_type(TextureStage::CombineMode cm) const;
-  GLint get_texture_src_type(TextureStage::CombineSource cs) const;
-  GLint get_texture_operand_type(TextureStage::CombineOperand co) const;
-  GLenum get_fog_mode_type(Fog::Mode m) const;
+  GLenum get_texture_wrap_mode(Texture::WrapMode wm) const;
+  static GLenum get_texture_filter_type(Texture::FilterType ft);
+  static GLenum get_image_type(PixelBuffer::Type type);
+  GLint get_external_image_format(PixelBuffer::Format format) const;
+  static GLint get_internal_image_format(PixelBuffer::Format format);
+  static GLint get_texture_apply_mode_type(TextureStage::Mode am);
+  static GLint get_texture_combine_type(TextureStage::CombineMode cm);
+  static GLint get_texture_src_type(TextureStage::CombineSource cs);
+  static GLint get_texture_operand_type(TextureStage::CombineOperand co);
+  static GLenum get_fog_mode_type(Fog::Mode m);
+  static GLenum get_blend_equation_type(ColorBlendAttrib::Mode mode);
+  static GLenum get_blend_func(ColorBlendAttrib::Operand operand);
 
   static CPT(RenderState) get_untextured_state();
 
@@ -277,6 +279,9 @@ public:
   PFNGLACTIVETEXTUREPROC _glActiveTexture;
   PFNGLMULTITEXCOORD2FVPROC _glMultiTexCoord2fv;
 
+  PFNGLBLENDEQUATIONEXTPROC _glBlendEquation;
+  PFNGLBLENDCOLOREXTPROC _glBlendColor;
+
   GLenum _edge_clamp;
   GLenum _border_clamp;
   GLenum _mirror_repeat;

+ 72 - 2
panda/src/pgraph/colorBlendAttrib.I

@@ -24,8 +24,28 @@
 //               ColorBlendAttrib object.
 ////////////////////////////////////////////////////////////////////
 INLINE ColorBlendAttrib::
-ColorBlendAttrib(ColorBlendAttrib::Mode mode) :
-  _mode(mode)
+ColorBlendAttrib() :
+  _mode(M_none),
+  _a(O_one),
+  _b(O_one),
+  _color(Colorf::zero())
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorBlendAttrib::Constructor
+//       Access: Private
+//  Description: Use ColorBlendAttrib::make() to construct a new
+//               ColorBlendAttrib object.
+////////////////////////////////////////////////////////////////////
+INLINE ColorBlendAttrib::
+ColorBlendAttrib(ColorBlendAttrib::Mode mode,
+                 ColorBlendAttrib::Operand a, ColorBlendAttrib::Operand b,
+                 const Colorf &color) :
+  _mode(mode),
+  _a(a),
+  _b(b),
+  _color(color)
 {
 }
 
@@ -38,3 +58,53 @@ INLINE ColorBlendAttrib::Mode ColorBlendAttrib::
 get_mode() const {
   return _mode;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorBlendAttrib::get_operand_a
+//       Access: Published
+//  Description: Returns the multiplier for the first component.
+////////////////////////////////////////////////////////////////////
+INLINE ColorBlendAttrib::Operand ColorBlendAttrib::
+get_operand_a() const {
+  return _a;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorBlendAttrib::get_operand_b
+//       Access: Published
+//  Description: Returns the multiplier for the second component.
+////////////////////////////////////////////////////////////////////
+INLINE ColorBlendAttrib::Operand ColorBlendAttrib::
+get_operand_b() const {
+  return _b;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorBlendAttrib::get_color
+//       Access: Published
+//  Description: Returns the constant color associated with the attrib.
+////////////////////////////////////////////////////////////////////
+INLINE Colorf ColorBlendAttrib::
+get_color() const {
+  return _color;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorBlendAttrib::involves_constant_color
+//       Access: Published, Static
+//  Description: Returns true if the indicated operand uses the
+//               constant color, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool ColorBlendAttrib::
+involves_constant_color(Operand operand) {
+  switch (operand) {
+  case O_constant_color:
+  case O_one_minus_constant_color:
+  case O_constant_alpha:
+  case O_one_minus_constant_alpha:
+    return true;
+
+  default:
+    return false;
+  }
+}

+ 150 - 22
panda/src/pgraph/colorBlendAttrib.cxx

@@ -26,14 +26,45 @@
 
 TypeHandle ColorBlendAttrib::_type_handle;
 
+////////////////////////////////////////////////////////////////////
+//     Function: ColorBlendAttrib::make_off
+//       Access: Published, Static
+//  Description: Constructs a new ColorBlendAttrib object that
+//               disables special-effect blending, allowing normal
+//               transparency to be used instead.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) ColorBlendAttrib::
+make_off() {
+  ColorBlendAttrib *attrib = new ColorBlendAttrib;
+  return return_new(attrib);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ColorBlendAttrib::make
 //       Access: Published, Static
-//  Description: Constructs a new ColorBlendAttrib object.
+//  Description: Constructs a new ColorBlendAttrib object.  This
+//               constructor is deprecated; use the one below, which
+//               takes three or four parameters, instead.
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) ColorBlendAttrib::
 make(ColorBlendAttrib::Mode mode) {
-  ColorBlendAttrib *attrib = new ColorBlendAttrib(mode);
+  ColorBlendAttrib *attrib = new ColorBlendAttrib(mode, O_one, O_one,
+                                                  Colorf::zero());
+  return return_new(attrib);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorBlendAttrib::make
+//       Access: Published, Static
+//  Description: Constructs a new ColorBlendAttrib object that enables
+//               special-effect blending.  This supercedes
+//               transparency.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) ColorBlendAttrib::
+make(ColorBlendAttrib::Mode mode, 
+     ColorBlendAttrib::Operand a, ColorBlendAttrib::Operand b,
+     const Colorf &color) {
+  ColorBlendAttrib *attrib = new ColorBlendAttrib(mode, a, b, color);
   return return_new(attrib);
 }
 
@@ -58,23 +89,16 @@ issue(GraphicsStateGuardianBase *gsg) const {
 ////////////////////////////////////////////////////////////////////
 void ColorBlendAttrib::
 output(ostream &out) const {
-  out << get_type() << ":";
-  switch (get_mode()) {
-  case M_none:
-    out << "none";
-    break;
-
-  case M_multiply:
-    out << "multiply";
-    break;
-
-  case M_add:
-    out << "add";
-    break;
-
-  case M_multiply_add:
-    out << "multiply_add";
-    break;
+  out << get_type() << ":" << get_mode();
+
+  if (get_mode() != M_none) {
+    out << "(" << get_operand_a()
+        << "," << get_operand_b();
+    if (involves_constant_color(get_operand_a()) ||
+        involves_constant_color(get_operand_b())) {
+      out << "," << get_color();
+    }
+    out << ")";
   }
 }
 
@@ -97,7 +121,20 @@ int ColorBlendAttrib::
 compare_to_impl(const RenderAttrib *other) const {
   const ColorBlendAttrib *ta;
   DCAST_INTO_R(ta, other, 0);
-  return (int)_mode - (int)ta->_mode;
+
+  if (_mode != ta->_mode) {
+    return (int)_mode - (int)ta->_mode;
+  }
+
+  if (_a != ta->_a) {
+    return (int)_a - (int)ta->_a;
+  }
+
+  if (_b != ta->_b) {
+    return (int)_b - (int)ta->_b;
+  }
+
+  return _color.compare_to(ta->_color);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -137,7 +174,10 @@ void ColorBlendAttrib::
 write_datagram(BamWriter *manager, Datagram &dg) {
   RenderAttrib::write_datagram(manager, dg);
 
-  dg.add_int8(_mode);
+  dg.add_uint8(_mode);
+  dg.add_uint8(_a);
+  dg.add_uint8(_b);
+  _color.write_datagram(dg);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -171,5 +211,93 @@ void ColorBlendAttrib::
 fillin(DatagramIterator &scan, BamReader *manager) {
   RenderAttrib::fillin(scan, manager);
 
-  _mode = (Mode)scan.get_int8();
+  _mode = (Mode)scan.get_uint8();
+  _a = (Operand)scan.get_uint8();
+  _b = (Operand)scan.get_uint8();
+  _color.read_datagram(scan);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ostream << ColorBlendAttrib::Mode
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ostream &
+operator << (ostream &out, ColorBlendAttrib::Mode mode) {
+  switch (mode) {
+  case ColorBlendAttrib::M_none:
+    return out << "none";
+
+  case ColorBlendAttrib::M_add:
+    return out << "add";
+
+  case ColorBlendAttrib::M_subtract:
+    return out << "subtract";
+
+  case ColorBlendAttrib::M_inv_subtract:
+    return out << "inv_subtract";
+
+  case ColorBlendAttrib::M_min:
+    return out << "min";
+
+  case ColorBlendAttrib::M_max:
+    return out << "max";
+  }
+
+  return out << "**invalid ColorBlendAttrib::Mode(" << (int)mode << ")**";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ostream << ColorBlendAttrib::Operand
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ostream &
+operator << (ostream &out, ColorBlendAttrib::Operand operand) {
+  switch (operand) {
+  case ColorBlendAttrib::O_zero:
+    return out << "0";
+
+  case ColorBlendAttrib::O_one:
+    return out << "1";
+
+  case ColorBlendAttrib::O_incoming_color:
+    return out << "ic";
+
+  case ColorBlendAttrib::O_one_minus_incoming_color:
+    return out << "1-ic";
+
+  case ColorBlendAttrib::O_fbuffer_color:
+    return out << "fc";
+
+  case ColorBlendAttrib::O_one_minus_fbuffer_color:
+    return out << "1-fc";
+
+  case ColorBlendAttrib::O_incoming_alpha:
+    return out << "ia";
+
+  case ColorBlendAttrib::O_one_minus_incoming_alpha:
+    return out << "1-ia";
+
+  case ColorBlendAttrib::O_fbuffer_alpha:
+    return out << "fa";
+
+  case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
+    return out << "1-fa";
+
+  case ColorBlendAttrib::O_constant_color:
+    return out << "cc";
+
+  case ColorBlendAttrib::O_one_minus_constant_color:
+    return out << "1-cc";
+
+  case ColorBlendAttrib::O_constant_alpha:
+    return out << "ca";
+
+  case ColorBlendAttrib::O_one_minus_constant_alpha:
+    return out << "1-ca";
+
+  case ColorBlendAttrib::O_incoming_color_saturate:
+    return out << "ics";
+  }
+
+  return out << "**invalid ColorBlendAttrib::Operand(" << (int)operand << ")**";
 }

+ 40 - 6
panda/src/pgraph/colorBlendAttrib.h

@@ -20,7 +20,7 @@
 #define COLORBLENDATTRIB_H
 
 #include "pandabase.h"
-
+#include "luse.h"
 #include "renderAttrib.h"
 
 class FactoryParams;
@@ -35,19 +35,48 @@ class EXPCL_PANDA ColorBlendAttrib : public RenderAttrib {
 PUBLISHED:
   enum Mode {
     M_none,             // Blending is disabled
-    M_multiply,         // color already in fbuffer * incoming color
-    M_add,              // color already in fbuffer + incoming color
-    M_multiply_add,     // color already in fbuffer * incoming color +
-                        //   color already in fbuffer
+    M_add,              // incoming color * A + fbuffer color * B
+    M_subtract,         // incoming color * A - fbuffer color * B
+    M_inv_subtract,     // fbuffer color * B - incoming color * A
+    M_min,              // min(incoming color, fbuffer color)
+    M_max               // max(incoming color, fbuffer color)
+  };
+
+  enum Operand {
+    O_zero,
+    O_one,
+    O_incoming_color,
+    O_one_minus_incoming_color,
+    O_fbuffer_color,
+    O_one_minus_fbuffer_color,
+    O_incoming_alpha,
+    O_one_minus_incoming_alpha,
+    O_fbuffer_alpha,
+    O_one_minus_fbuffer_alpha,
+    O_constant_color,
+    O_one_minus_constant_color,
+    O_constant_alpha,
+    O_one_minus_constant_alpha,
+    O_incoming_color_saturate,  // valid only for operand a
   };
 
 private:
-  INLINE ColorBlendAttrib(Mode mode = M_none);
+  INLINE ColorBlendAttrib();
+  INLINE ColorBlendAttrib(Mode mode, Operand a, Operand b,
+                          const Colorf &color);
 
 PUBLISHED:
+  static CPT(RenderAttrib) make_off();
   static CPT(RenderAttrib) make(Mode mode);
+  static CPT(RenderAttrib) make(Mode mode, Operand a, Operand b,
+                                const Colorf &color = Colorf::zero());
 
   INLINE Mode get_mode() const;
+  INLINE Operand get_operand_a() const;
+  INLINE Operand get_operand_b() const;
+  INLINE Colorf get_color() const;
+
+  INLINE static bool involves_constant_color(Operand operand);
 
 public:
   virtual void issue(GraphicsStateGuardianBase *gsg) const;
@@ -59,6 +88,8 @@ protected:
 
 private:
   Mode _mode;
+  Operand _a, _b;
+  Colorf _color;
 
 public:
   static void register_with_read_factory();
@@ -86,6 +117,9 @@ private:
   static TypeHandle _type_handle;
 };
 
+ostream &operator << (ostream &out, ColorBlendAttrib::Mode mode);
+ostream &operator << (ostream &out, ColorBlendAttrib::Operand operand);
+
 #include "colorBlendAttrib.I"
 
 #endif