diff --git a/cogl/cogl-atlas-texture.c b/cogl/cogl-atlas-texture.c index 4bbff22ea..1400919d5 100644 --- a/cogl/cogl-atlas-texture.c +++ b/cogl/cogl-atlas-texture.c @@ -419,6 +419,90 @@ _cogl_atlas_texture_ensure_non_quad_rendering (CoglTexture *tex) _cogl_texture_ensure_non_quad_rendering (atlas_tex->sub_texture); } +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, @@ -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; - _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)) + /* Check for valid format */ + if (format == COGL_PIXEL_FORMAT_ANY) 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; + /* Shortcut out early if the image is empty */ + if (width == 0 || height == 0) + return TRUE; - return TRUE; + /* Init source bitmap */ + source_bmp.width = width; + source_bmp.height = height; + source_bmp.format = format; + source_bmp.data = (guchar*) data; + + /* Rowstride from width if none specified */ + bpp = _cogl_get_format_bpp (format); + source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride; + + /* 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); + + /* 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); }