Add premultiplied alpha mode, for convenience

This commit is contained in:
rdb 2016-03-02 17:55:34 +01:00
parent 2971915618
commit 2bf886fc5b
13 changed files with 63 additions and 13 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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;
}

View File

@ -692,6 +692,9 @@ convert_primitive(const GeomVertexData *vertex_data,
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) {

View File

@ -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);

View File

@ -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());

View File

@ -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());
}

View File

@ -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";

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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;
}