Ver Fonte

Add premultiplied alpha mode, for convenience

rdb há 9 anos atrás
pai
commit
2bf886fc5b

+ 7 - 0
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -3822,6 +3822,13 @@ do_issue_blending() {
     set_render_state(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
     return;
 
+  case TransparencyAttrib::M_premultiplied_alpha:
+    set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
+    set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
+    set_render_state(D3DRS_SRCBLEND, D3DBLEND_ONE);
+    set_render_state(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
+    return;
+
   default:
     dxgsg9_cat.error()
       << "invalid transparency mode " << (int)transparency_mode << endl;

+ 4 - 0
panda/src/egg/eggRenderMode.cxx

@@ -183,6 +183,8 @@ string_alpha_mode(const string &string) {
     return AM_binary;
   } else if (cmp_nocase_uh(string, "dual") == 0) {
     return AM_dual;
+  } else if (cmp_nocase_uh(string, "premultiplied") == 0) {
+    return AM_premultiplied;
   } else {
     return AM_unspecified;
   }
@@ -260,6 +262,8 @@ ostream &operator << (ostream &out, EggRenderMode::AlphaMode mode) {
     return out << "binary";
   case EggRenderMode::AM_dual:
     return out << "dual";
+  case EggRenderMode::AM_premultiplied:
+    return out << "premultiplied";
   }
 
   nassertr(false, out);

+ 2 - 1
panda/src/egg/eggRenderMode.h

@@ -45,7 +45,8 @@ PUBLISHED:
     AM_ms,      // TransparencyAttrib::M_multisample
     AM_ms_mask, // TransparencyAttrib::M_multisample_mask
     AM_binary,  // TransparencyAttrib::M_binary
-    AM_dual     // TransparencyAttrib::M_dual
+    AM_dual,    // TransparencyAttrib::M_dual
+    AM_premultiplied // TransparencyAttrib::M_premultiplied_alpha
   };
 
   enum DepthWriteMode {

+ 4 - 0
panda/src/egg2pg/eggRenderState.cxx

@@ -333,6 +333,10 @@ fill_state(EggPrimitive *egg_prim) {
     add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_dual));
     break;
 
+  case EggRenderMode::AM_premultiplied:
+    add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_premultiplied_alpha));
+    break;
+
   default:
     break;
   }

+ 5 - 3
panda/src/egg2pg/eggSaver.cxx

@@ -686,12 +686,15 @@ convert_primitive(const GeomVertexData *vertex_data,
         break;
       case TransparencyAttrib::M_alpha:
         if (has_depthwrite && (depthwrite == DepthWriteAttrib::M_off)) {
-            tex_trans = EggRenderMode::AM_blend_no_occlude;
-                has_depthwrite = false;
+          tex_trans = EggRenderMode::AM_blend_no_occlude;
+          has_depthwrite = false;
         } else {
           tex_trans = EggRenderMode::AM_blend;
         }
         break;
+      case TransparencyAttrib::M_premultiplied_alpha:
+        tex_trans = EggRenderMode::AM_premultiplied;
+        break;
       case TransparencyAttrib::M_multisample:
         tex_trans = EggRenderMode::AM_ms;
         break;
@@ -705,7 +708,6 @@ convert_primitive(const GeomVertexData *vertex_data,
         tex_trans = EggRenderMode::AM_dual;
         break;
       default:  // intentional fall-through
-      case TransparencyAttrib::M_notused:
         break;
     }
     if (tex_trans != EggRenderMode::AM_unspecified) {

+ 13 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -6722,6 +6722,19 @@ do_issue_blending() {
     }
     return;
 
+  case TransparencyAttrib::M_premultiplied_alpha:
+    enable_multisample_alpha_one(false);
+    enable_multisample_alpha_mask(false);
+    enable_blend(true);
+    _glBlendEquation(GL_FUNC_ADD);
+    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+    if (GLCAT.is_spam()) {
+      GLCAT.spam() << "glBlendEquation(GL_FUNC_ADD)\n";
+      GLCAT.spam() << "glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)\n";
+    }
+    return;
+
   case TransparencyAttrib::M_multisample:
     // We need to enable *both* of these in M_multisample case.
     enable_multisample_alpha_one(true);

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

@@ -131,6 +131,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
   if (object->_state->get_attrib(trans)) {
     switch (trans->get_mode()) {
     case TransparencyAttrib::M_alpha:
+    case TransparencyAttrib::M_premultiplied_alpha:
       // M_alpha implies an alpha-write test, so we don't waste time writing
       // 0-valued pixels.
       object->_state = object->_state->compose(get_alpha_state());

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

@@ -47,7 +47,7 @@ apply_transform_and_state(CullTraverser *trav) {
   _node_reader.compose_draw_mask(_draw_mask);
 
   apply_transform_and_state(trav, _node_reader.get_transform(),
-                            node_state, _node_reader.get_effects(),
+                            MOVE(node_state), _node_reader.get_effects(),
                             _node_reader.get_off_clip_planes());
 }
 

+ 5 - 4
panda/src/pgraph/renderState.cxx

@@ -1853,8 +1853,8 @@ determine_bin_index() {
   string bin_name;
   _draw_order = 0;
 
-  const CullBinAttrib *bin = DCAST(CullBinAttrib, get_attrib(CullBinAttrib::get_class_slot()));
-  if (bin != (const CullBinAttrib *)NULL) {
+  const CullBinAttrib *bin;
+  if (get_attrib(bin)) {
     bin_name = bin->get_bin_name();
     _draw_order = bin->get_draw_order();
   }
@@ -1864,10 +1864,11 @@ determine_bin_index() {
     // opaque or transparent, based on the transparency setting.
     bin_name = "opaque";
 
-    const TransparencyAttrib *transparency = DCAST(TransparencyAttrib, get_attrib(TransparencyAttrib::get_class_slot()));
-    if (transparency != (const TransparencyAttrib *)NULL) {
+    const TransparencyAttrib *transparency;
+    if (get_attrib(transparency)) {
       switch (transparency->get_mode()) {
       case TransparencyAttrib::M_alpha:
+      case TransparencyAttrib::M_premultiplied_alpha:
       case TransparencyAttrib::M_dual:
         // These transparency modes require special back-to-front sorting.
         bin_name = "transparent";

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

@@ -55,6 +55,10 @@ output(ostream &out) const {
     out << "alpha";
     break;
 
+  case M_premultiplied_alpha:
+    out << "premultiplied alpha";
+    break;
+
   case M_multisample:
     out << "multisample";
     break;
@@ -70,9 +74,6 @@ output(ostream &out) const {
   case M_dual:
     out << "dual";
     break;
-
-  case M_notused:
-    break;
   }
 }
 

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

@@ -36,7 +36,7 @@ PUBLISHED:
     // corresponded to M_none or M_alpha).
     M_none = 0,         // No transparency.
     M_alpha = 1,        // Normal transparency, panda will sort back-to-front.
-    M_notused,          // Unused placeholder.  Do not use this.
+    M_premultiplied_alpha, // Assume textures use premultiplied alpha.
     M_multisample,      // Uses ms buffer, alpha values modified to 1.0.
     M_multisample_mask, // Uses ms buffer, alpha values not modified.
     M_binary,           // Only writes pixels with alpha >= 0.5.

+ 1 - 0
panda/src/pgraphnodes/shaderGenerator.cxx

@@ -209,6 +209,7 @@ analyze_renderstate(const RenderState *rs) {
   const TransparencyAttrib *transparency;
   rs->get_attrib_def(transparency);
   if ((transparency->get_mode() == TransparencyAttrib::M_alpha)||
+      (transparency->get_mode() == TransparencyAttrib::M_premultiplied_alpha)||
       (transparency->get_mode() == TransparencyAttrib::M_dual)) {
     _have_alpha_blend = true;
   }

+ 15 - 0
panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx

@@ -804,6 +804,21 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
     }
     break;
 
+  case TransparencyAttrib::M_premultiplied_alpha:
+    {
+      // Implement a color mask, with pre-multiplied alpha blending.
+      int op_a = get_color_blend_op(ColorBlendAttrib::O_one);
+      int op_b = get_color_blend_op(ColorBlendAttrib::O_one_minus_incoming_alpha);
+
+      if (srgb_blend) {
+        _c->zb->store_pix_func = store_pixel_funcs_sRGB[op_a][op_b][color_channels];
+      } else {
+        _c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
+      }
+      color_write_state = 2;   // cgeneral
+    }
+    break;
+
   default:
     break;
   }