diff --git a/common/cogl-bitmap-fallback.c b/common/cogl-bitmap-fallback.c index e118459e1..a7e9704d9 100644 --- a/common/cogl-bitmap-fallback.c +++ b/common/cogl-bitmap-fallback.c @@ -180,6 +180,41 @@ _cogl_unpremult_alpha_first (const guchar *src, guchar *dst) dst[3] = ((((gulong) src[3] >> 0) & 0xff) * 255 ) / alpha; } +/* No division form of floor((c*a + 128)/255) (I first encountered + * this in the RENDER implementation in the X server.) Being exact + * is important for a == 255 - we want to get exactly c. + */ +#define MULT(d,c,a,t) G_STMT_START { t = c * a + 128; d = ((t >> 8) + t) >> 8; } G_STMT_END + +inline static void +_cogl_premult_alpha_last (const guchar *src, guchar *dst) +{ + guchar alpha = src[3]; + /* Using a separate temporary per component has given slightly better + * code generation with GCC in the past; it shouldn't do any worse in + * any case. + */ + guint t1, t2, t3; + MULT(dst[0], src[0], alpha, t1); + MULT(dst[1], src[1], alpha, t2); + MULT(dst[2], src[2], alpha, t3); + dst[3] = alpha; +} + +inline static void +_cogl_premult_alpha_first (const guchar *src, guchar *dst) +{ + guchar alpha = src[0]; + guint t1, t2, t3; + + dst[0] = alpha; + MULT(dst[1], src[1], alpha, t1); + MULT(dst[2], src[2], alpha, t2); + MULT(dst[3], src[3], alpha, t3); +} + +#undef MULT + gboolean _cogl_bitmap_fallback_can_convert (CoglPixelFormat src, CoglPixelFormat dst) { @@ -211,6 +246,12 @@ _cogl_bitmap_fallback_can_unpremult (CoglPixelFormat format) return ((format & COGL_UNORDERED_MASK) == COGL_PIXEL_FORMAT_32); } +gboolean +_cogl_bitmap_fallback_can_premult (CoglPixelFormat format) +{ + return ((format & COGL_UNORDERED_MASK) == COGL_PIXEL_FORMAT_32); +} + gboolean _cogl_bitmap_fallback_convert (const CoglBitmap *bmp, CoglBitmap *dst_bmp, @@ -358,6 +399,58 @@ _cogl_bitmap_fallback_unpremult (const CoglBitmap *bmp, return TRUE; } +gboolean +_cogl_bitmap_fallback_premult (const CoglBitmap *bmp, + CoglBitmap *dst_bmp) +{ + guchar *src; + guchar *dst; + gint bpp; + gint x,y; + + /* Make sure format supported for un-premultiplication */ + if (!_cogl_bitmap_fallback_can_premult (bmp->format)) + return FALSE; + + bpp = _cogl_get_format_bpp (bmp->format); + + /* Initialize destination bitmap */ + *dst_bmp = *bmp; + dst_bmp->format = (bmp->format & COGL_UNPREMULT_MASK); + + /* Allocate a new buffer to hold converted data */ + dst_bmp->data = g_malloc (sizeof(guchar) + * dst_bmp->height + * dst_bmp->rowstride); + + for (y = 0; y < bmp->height; y++) + { + src = (guchar*)bmp->data + y * bmp->rowstride; + dst = (guchar*)dst_bmp->data + y * dst_bmp->rowstride; + + if (bmp->format & COGL_AFIRST_BIT) + { + for (x = 0; x < bmp->width; x++) + { + _cogl_premult_alpha_first (src, dst); + src += bpp; + dst += bpp; + } + } + else + { + for (x = 0; x < bmp->width; x++) + { + _cogl_premult_alpha_last (src, dst); + src += bpp; + dst += bpp; + } + } + } + + return TRUE; +} + gboolean _cogl_bitmap_fallback_from_file (CoglBitmap *bmp, const gchar *filename) diff --git a/common/cogl-bitmap-pixbuf.c b/common/cogl-bitmap-pixbuf.c index f1e500534..1b75cd0ba 100644 --- a/common/cogl-bitmap-pixbuf.c +++ b/common/cogl-bitmap-pixbuf.c @@ -49,6 +49,12 @@ _cogl_bitmap_can_unpremult (CoglPixelFormat format) return FALSE; } +gboolean +_cogl_bitmap_can_premult (CoglPixelFormat format) +{ + return FALSE; +} + gboolean _cogl_bitmap_convert (const CoglBitmap *bmp, CoglBitmap *dst_bmp, @@ -64,6 +70,13 @@ _cogl_bitmap_unpremult (const CoglBitmap *bmp, return FALSE; } +gboolean +_cogl_bitmap_premult (const CoglBitmap *bmp, + CoglBitmap *dst_bmp) +{ + return FALSE; +} + #ifdef USE_QUARTZ /* lacking GdkPixbuf and other useful GError domains, define one of our own */ diff --git a/common/cogl-bitmap-private.h b/common/cogl-bitmap-private.h index f54961bd0..b6e425733 100644 --- a/common/cogl-bitmap-private.h +++ b/common/cogl-bitmap-private.h @@ -52,6 +52,12 @@ _cogl_bitmap_can_unpremult (CoglPixelFormat format); gboolean _cogl_bitmap_fallback_can_unpremult (CoglPixelFormat format); +gboolean +_cogl_bitmap_can_premult (CoglPixelFormat format); + +gboolean +_cogl_bitmap_fallback_can_premult (CoglPixelFormat format); + gboolean _cogl_bitmap_convert (const CoglBitmap *bmp, CoglBitmap *dst_bmp, @@ -69,6 +75,14 @@ gboolean _cogl_bitmap_fallback_unpremult (const CoglBitmap *bmp, CoglBitmap *dst_bmp); +gboolean +_cogl_bitmap_premult (const CoglBitmap *bmp, + CoglBitmap *dst_bmp); + +gboolean +_cogl_bitmap_fallback_premult (const CoglBitmap *bmp, + CoglBitmap *dst_bmp); + gboolean _cogl_bitmap_from_file (CoglBitmap *bmp, const gchar *filename, diff --git a/common/cogl-bitmap.c b/common/cogl-bitmap.c index f4c322abb..3dc7fd534 100644 --- a/common/cogl-bitmap.c +++ b/common/cogl-bitmap.c @@ -87,8 +87,8 @@ _cogl_bitmap_convert_and_premult (const CoglBitmap *bmp, } /* Do we need to unpremultiply */ - if ((bmp->format & COGL_PREMULT_BIT) == 0 && - (dst_format & COGL_PREMULT_BIT) > 0) + if ((bmp->format & COGL_PREMULT_BIT) > 0 && + (dst_format & COGL_PREMULT_BIT) == 0) { /* Try unpremultiplying using imaging library */ if (!_cogl_bitmap_unpremult (&new_bmp, &tmp_bmp)) @@ -112,14 +112,28 @@ _cogl_bitmap_convert_and_premult (const CoglBitmap *bmp, } /* Do we need to premultiply */ - if ((bmp->format & COGL_PREMULT_BIT) > 0 && - (dst_format & COGL_PREMULT_BIT) == 0) + if ((bmp->format & COGL_PREMULT_BIT) == 0 && + (dst_format & COGL_PREMULT_BIT) > 0) { - /* FIXME: implement premultiplication */ + /* Try premultiplying using imaging library */ + if (!_cogl_bitmap_premult (&new_bmp, &tmp_bmp)) + { + /* ... or try fallback */ + if (!_cogl_bitmap_fallback_premult (&new_bmp, &tmp_bmp)) + { + if (new_bmp_owner) + g_free (new_bmp.data); + + return FALSE; + } + } + + /* Update bitmap with new data */ if (new_bmp_owner) g_free (new_bmp.data); - return FALSE; + new_bmp = tmp_bmp; + new_bmp_owner = TRUE; } /* Output new bitmap info */