From c4adefffd34d91fdf72365a6d11641f3c9f751cc Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Mon, 18 Jan 2010 10:53:00 +0000 Subject: [PATCH] cogl-atlas-texture: Fix premultiplied texture formats When uploading texture data it was just calling cogl_texture_set_data on the large texture. This would attempt to convert the data to the format of the large texture. All of the textures with alpha channels are stored together regardless of whether they are premultiplied so this was causing premultiplied textures to be unpremultiplied again. It now just uploads the data ignoring the premult bit of the format so that it only gets converted once. --- clutter/cogl/cogl/cogl-atlas-texture.c | 232 ++++++++++++++++++++++----------- 1 file changed, 158 insertions(+), 74 deletions(-) diff --git a/clutter/cogl/cogl/cogl-atlas-texture.c b/clutter/cogl/cogl/cogl-atlas-texture.c index 4bbff22..1400919 100644 --- a/clutter/cogl/cogl/cogl-atlas-texture.c +++ b/clutter/cogl/cogl/cogl-atlas-texture.c @@ -420,6 +420,90 @@ _cogl_atlas_texture_ensure_non_quad_rendering (CoglTexture *tex) } static gboolean +_cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int dst_width, + unsigned int dst_height, + int width, + int height, + CoglPixelFormat format, + unsigned int rowstride, + const guint8 *data) +{ + CoglHandle big_texture; + + _COGL_GET_CONTEXT (ctx, FALSE); + + big_texture = ((atlas_tex->format & COGL_A_BIT) ? + ctx->atlas_alpha_texture : ctx->atlas_no_alpha_texture); + + /* Copy the central data */ + if (!cogl_texture_set_region (big_texture, + src_x, src_y, + dst_x + atlas_tex->rectangle.x + 1, + dst_y + atlas_tex->rectangle.y + 1, + dst_width, + dst_height, + width, height, + format, + rowstride, + data)) + return FALSE; + + /* Update the left edge pixels */ + if (dst_x == 0 && + !cogl_texture_set_region (big_texture, + src_x, src_y, + atlas_tex->rectangle.x, + dst_y + atlas_tex->rectangle.y + 1, + 1, dst_height, + width, height, + format, rowstride, + data)) + return FALSE; + /* Update the right edge pixels */ + if (dst_x + dst_width == atlas_tex->rectangle.width - 2 && + !cogl_texture_set_region (big_texture, + src_x + dst_width - 1, src_y, + atlas_tex->rectangle.x + + atlas_tex->rectangle.width - 1, + dst_y + atlas_tex->rectangle.y + 1, + 1, dst_height, + width, height, + format, rowstride, + data)) + return FALSE; + /* Update the top edge pixels */ + if (dst_y == 0 && + !cogl_texture_set_region (big_texture, + src_x, src_y, + dst_x + atlas_tex->rectangle.x + 1, + atlas_tex->rectangle.y, + dst_width, 1, + width, height, + format, rowstride, + data)) + return FALSE; + /* Update the bottom edge pixels */ + if (dst_y + dst_height == atlas_tex->rectangle.height - 2 && + !cogl_texture_set_region (big_texture, + src_x, src_y + dst_height - 1, + dst_x + atlas_tex->rectangle.x + 1, + atlas_tex->rectangle.y + + atlas_tex->rectangle.height - 1, + dst_width, 1, + width, height, + format, rowstride, + data)) + return FALSE; + + return TRUE; +} + +static gboolean _cogl_atlas_texture_set_region (CoglTexture *tex, int src_x, int src_y, @@ -439,74 +523,71 @@ _cogl_atlas_texture_set_region (CoglTexture *tex, pixels to the border */ if (atlas_tex->in_atlas) { - CoglHandle big_texture; + gint bpp; + CoglBitmap source_bmp; + CoglBitmap temp_bmp; + gboolean source_bmp_owner = FALSE; + CoglPixelFormat closest_format; + GLenum closest_gl_format; + GLenum closest_gl_type; + gboolean success; + + /* Check for valid format */ + if (format == COGL_PIXEL_FORMAT_ANY) + return FALSE; - _COGL_GET_CONTEXT (ctx, FALSE); + /* Shortcut out early if the image is empty */ + if (width == 0 || height == 0) + return TRUE; - big_texture = ((atlas_tex->format & COGL_A_BIT) ? - ctx->atlas_alpha_texture : ctx->atlas_no_alpha_texture); + /* Init source bitmap */ + source_bmp.width = width; + source_bmp.height = height; + source_bmp.format = format; + source_bmp.data = (guchar*) data; - /* Copy the central data */ - if (!cogl_texture_set_region (big_texture, - src_x, src_y, - dst_x + atlas_tex->rectangle.x + 1, - dst_y + atlas_tex->rectangle.y + 1, - dst_width, - dst_height, - width, height, - format, - rowstride, - data)) - return FALSE; + /* Rowstride from width if none specified */ + bpp = _cogl_get_format_bpp (format); + source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride; - /* Update the left edge pixels */ - if (dst_x == 0 && - !cogl_texture_set_region (big_texture, - src_x, src_y, - atlas_tex->rectangle.x, - dst_y + atlas_tex->rectangle.y + 1, - 1, dst_height, - width, height, - format, rowstride, - data)) - return FALSE; - /* Update the right edge pixels */ - if (dst_x + dst_width == atlas_tex->rectangle.width - 2 && - !cogl_texture_set_region (big_texture, - src_x + dst_width - 1, src_y, - atlas_tex->rectangle.x + - atlas_tex->rectangle.width - 1, - dst_y + atlas_tex->rectangle.y + 1, - 1, dst_height, - width, height, - format, rowstride, - data)) - return FALSE; - /* Update the top edge pixels */ - if (dst_y == 0 && - !cogl_texture_set_region (big_texture, - src_x, src_y, - dst_x + atlas_tex->rectangle.x + 1, - atlas_tex->rectangle.y, - dst_width, 1, - width, height, - format, rowstride, - data)) - return FALSE; - /* Update the bottom edge pixels */ - if (dst_y + dst_height == atlas_tex->rectangle.height - 2 && - !cogl_texture_set_region (big_texture, - src_x, src_y + dst_height - 1, - dst_x + atlas_tex->rectangle.x + 1, - atlas_tex->rectangle.y + - atlas_tex->rectangle.height - 1, - dst_width, 1, - width, height, - format, rowstride, - data)) - return FALSE; + /* Find closest format to internal that's supported by GL */ + closest_format = _cogl_pixel_format_to_gl (atlas_tex->format, + NULL, /* don't need */ + &closest_gl_format, + &closest_gl_type); - return TRUE; + /* If no direct match, convert */ + if (closest_format != format) + { + /* Convert to required format */ + success = _cogl_bitmap_convert_and_premult (&source_bmp, + &temp_bmp, + closest_format); + + /* Swap bitmaps if succeeded */ + if (!success) return FALSE; + source_bmp = temp_bmp; + source_bmp_owner = TRUE; + } + + /* Upload the data ignoring the premult bit */ + success = + _cogl_atlas_texture_set_region_with_border (atlas_tex, + src_x, src_y, + dst_x, dst_y, + dst_width, dst_height, + source_bmp.width, + source_bmp.height, + source_bmp.format & + ~COGL_PREMULT_BIT, + source_bmp.rowstride, + source_bmp.data); + + /* Free data if owner */ + if (source_bmp_owner) + g_free (source_bmp.data); + + return success; } else /* Otherwise we can just forward on to the sub texture */ @@ -962,17 +1043,20 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle bmp_handle, &atlas_tex->rectangle); /* Defer to set_region so that we can share the code for copying the - edge pixels to the border */ - _cogl_atlas_texture_set_region (COGL_TEXTURE (atlas_tex), - 0, 0, - 0, 0, - upload_data.bitmap.width, - upload_data.bitmap.height, - upload_data.bitmap.width, - upload_data.bitmap.height, - upload_data.bitmap.format, - upload_data.bitmap.rowstride, - upload_data.bitmap.data); + edge pixels to the border. We don't want to pass the actual + format of the converted texture because otherwise it will get + unpremultiplied. */ + _cogl_atlas_texture_set_region_with_border (atlas_tex, + 0, 0, + 0, 0, + upload_data.bitmap.width, + upload_data.bitmap.height, + upload_data.bitmap.width, + upload_data.bitmap.height, + upload_data.bitmap.format & + ~COGL_PREMULT_BIT, + upload_data.bitmap.rowstride, + upload_data.bitmap.data); return _cogl_atlas_texture_handle_new (atlas_tex); } -- 2.7.4