From 099d6d1b505b55bbd09c50d081deb41ab5764e19 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Wed, 9 May 2012 19:43:06 +0100 Subject: bitmap: Adds cogl_android_bitmap_new_from_asset() This adds some android specific api for creating a CoglBitmap from an Android asset. As part of the work it also seemed like a good time to change the internal bitmap constructors to take an explicit CoglContext argument and so the public cogl_bitmap_new_from_file() api was also changed accordingly to take a CoglContext pointer as the first argument. Reviewed-by: Neil Roberts --- cogl/cogl-bitmap-pixbuf.c | 203 ++++++++++++++++++++++++++++++++++++++------- cogl/cogl-bitmap-private.h | 17 +++- cogl/cogl-bitmap.c | 24 +++++- cogl/cogl-bitmap.h | 30 ++++++- cogl/cogl-texture.c | 4 +- 5 files changed, 241 insertions(+), 37 deletions(-) diff --git a/cogl/cogl-bitmap-pixbuf.c b/cogl/cogl-bitmap-pixbuf.c index abbf0cdf..d30a8518 100644 --- a/cogl/cogl-bitmap-pixbuf.c +++ b/cogl/cogl-bitmap-pixbuf.c @@ -29,6 +29,7 @@ #include "cogl-internal.h" #include "cogl-bitmap-private.h" #include "cogl-context-private.h" +#include "cogl-private.h" #include @@ -56,8 +57,9 @@ _cogl_bitmap_get_size_from_file (const char *filename, /* the error does not contain the filename as the caller already has it */ CoglBitmap * -_cogl_bitmap_from_file (const char *filename, - GError **error) +_cogl_bitmap_from_file (CoglContext *ctx, + const char *filename, + GError **error) { CFURLRef url; CGImageSourceRef image_source; @@ -70,11 +72,6 @@ _cogl_bitmap_from_file (const char *filename, CGContextRef bitmap_context; CoglBitmap *bmp; - _COGL_GET_CONTEXT (ctx, NULL); - - g_assert (filename != NULL); - g_assert (error == NULL || *error == NULL); - url = CFURLCreateFromFileSystemRepresentation (NULL, (guchar *) filename, strlen (filename), @@ -173,8 +170,9 @@ _cogl_bitmap_get_size_from_file (const char *filename, } CoglBitmap * -_cogl_bitmap_from_file (const char *filename, - GError **error) +_cogl_bitmap_from_file (CoglContext *ctx, + const char *filename, + GError **error) { static CoglUserDataKey pixbuf_key; GdkPixbuf *pixbuf; @@ -188,10 +186,6 @@ _cogl_bitmap_from_file (const char *filename, int n_channels; CoglBitmap *bmp; - _COGL_GET_CONTEXT (ctx, NULL); - - _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, FALSE); - /* Load from file using GdkPixbuf */ pixbuf = gdk_pixbuf_new_from_file (filename, error); if (pixbuf == NULL) @@ -269,38 +263,187 @@ _cogl_bitmap_get_size_from_file (const char *filename, return TRUE; } -CoglBitmap * -_cogl_bitmap_from_file (const char *filename, - GError **error) +/* stb_image.c supports an STBI_grey_alpha format which we don't have + * a corresponding CoglPixelFormat for so as a special case we + * convert this to rgba8888. + * + * If we have a use case where this is an important format to consider + * then it could be worth adding a corresponding CoglPixelFormat + * instead. + */ +static uint8_t * +convert_ra_88_to_rgba_8888 (uint8_t *pixels, + int width, + int height) +{ + int x, y; + uint8_t *buf; + size_t in_stride = width * 2; + size_t out_stride = width * 4; + + buf = malloc (width * height * 4); + if (buf) + return NULL; + + for (y = 0; y < height; y++) + for (x = 0; x < width; x++) + { + uint8_t *src = pixels + in_stride * y + 2 * x; + uint8_t *dst = buf + out_stride * y + 4 * x; + + dst[0] = src[0]; + dst[1] = src[0]; + dst[2] = src[0]; + dst[3] = src[1]; + } + + return buf; +} + +static CoglBitmap * +_cogl_bitmap_new_from_stb_pixels (CoglContext *ctx, + uint8_t *pixels, + int stb_pixel_format, + int width, + int height, + GError **error) { static CoglUserDataKey bitmap_data_key; CoglBitmap *bmp; - int stb_pixel_format; - int width; - int height; - uint8_t *pixels; + CoglPixelFormat cogl_format; + size_t stride; - _COGL_GET_CONTEXT (ctx, NULL); + if (pixels == NULL) + { + g_set_error_literal (error, + COGL_BITMAP_ERROR, + COGL_BITMAP_ERROR_FAILED, + "Failed to load image with stb image library"); + return NULL; + } - _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, FALSE); + switch (stb_pixel_format) + { + case STBI_grey: + cogl_format = COGL_PIXEL_FORMAT_A_8; + break; + case STBI_grey_alpha: + { + uint8_t *tmp = pixels; + + pixels = convert_ra_88_to_rgba_8888 (pixels, width, height); + free (tmp); + + if (!pixels) + { + g_set_error_literal (error, + COGL_BITMAP_ERROR, + COGL_BITMAP_ERROR_FAILED, + "Failed to alloc memory to convert " + "gray_alpha to rgba8888"); + return NULL; + } + + cogl_format = COGL_PIXEL_FORMAT_RGBA_8888; + break; + } + case STBI_rgb: + cogl_format = COGL_PIXEL_FORMAT_RGB_888; + break; + case STBI_rgb_alpha: + cogl_format = COGL_PIXEL_FORMAT_RGBA_8888; + break; - /* Load from file using stb */ - pixels = stbi_load (filename, - &width, &height, &stb_pixel_format, - STBI_rgb_alpha); - if (pixels == NULL) - return FALSE; + default: + g_warn_if_reached (); + return NULL; + } + + stride = width * _cogl_pixel_format_get_bytes_per_pixel (cogl_format); /* Store bitmap info */ bmp = cogl_bitmap_new_for_data (ctx, width, height, - COGL_PIXEL_FORMAT_RGBA_8888, - width * 4, /* rowstride */ + cogl_format, + stride, pixels); + /* Register a destroy function so the pixel data will be freed automatically when the bitmap object is destroyed */ cogl_object_set_user_data (COGL_OBJECT (bmp), &bitmap_data_key, pixels, free); return bmp; } + +CoglBitmap * +_cogl_bitmap_from_file (CoglContext *ctx, + const char *filename, + GError **error) +{ + int stb_pixel_format; + int width; + int height; + uint8_t *pixels; + + pixels = stbi_load (filename, + &width, &height, &stb_pixel_format, + STBI_default); + + return _cogl_bitmap_new_from_stb_pixels (ctx, pixels, stb_pixel_format, + width, height, + error); +} + +#ifdef COGL_HAS_ANDROID_SUPPORT +CoglBitmap * +_cogl_android_bitmap_new_from_asset (CoglContext *ctx, + AAssetManager *manager, + const char *filename, + GError **error) +{ + AAsset *asset; + const void *data; + off_t len; + int stb_pixel_format; + int width; + int height; + uint8_t *pixels; + CoglBitmap *bmp; + + asset = AAssetManager_open (manager, filename, AASSET_MODE_BUFFER); + if (!asset) + { + g_set_error_literal (error, + COGL_BITMAP_ERROR, + COGL_BITMAP_ERROR_FAILED, + "Failed to open asset"); + return NULL; + } + + data = AAsset_getBuffer (asset); + if (!data) + { + g_set_error_literal (error, + COGL_BITMAP_ERROR, + COGL_BITMAP_ERROR_FAILED, + "Failed to ::getBuffer from asset"); + return NULL; + } + + len = AAsset_getLength (asset); + + pixels = stbi_load_from_memory (data, len, + &width, &height, + &stb_pixel_format, STBI_default); + + bmp = _cogl_bitmap_new_from_stb_pixels (ctx, pixels, stb_pixel_format, + width, height, + error); + + AAsset_close (asset); + + return bmp; +} +#endif + #endif diff --git a/cogl/cogl-bitmap-private.h b/cogl/cogl-bitmap-private.h index a95754ad..c74c862a 100644 --- a/cogl/cogl-bitmap-private.h +++ b/cogl/cogl-bitmap-private.h @@ -32,6 +32,10 @@ #include "cogl-buffer.h" #include "cogl-bitmap.h" +#ifdef COGL_HAS_ANDROID_SUPPORT +#include +#endif + struct _CoglBitmap { CoglObject _parent; @@ -103,8 +107,17 @@ _cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp, CoglBitmap *dst_bmp); CoglBitmap * -_cogl_bitmap_from_file (const char *filename, - GError **error); +_cogl_bitmap_from_file (CoglContext *ctx, + const char *filename, + GError **error); + +#ifdef COGL_HAS_ANDROID_SUPPORT +CoglBitmap * +_cogl_android_bitmap_new_from_asset (CoglContext *ctx, + AAssetManager *manager, + const char *filename, + GError **error); +#endif CoglBool _cogl_bitmap_unpremult (CoglBitmap *dst_bmp); diff --git a/cogl/cogl-bitmap.c b/cogl/cogl-bitmap.c index fb233dfd..af52de81 100644 --- a/cogl/cogl-bitmap.c +++ b/cogl/cogl-bitmap.c @@ -227,12 +227,14 @@ _cogl_bitmap_new_shared (CoglBitmap *shared_bmp, } CoglBitmap * -cogl_bitmap_new_from_file (const char *filename, - GError **error) +cogl_bitmap_new_from_file (CoglContext *ctx, + const char *filename, + GError **error) { + _COGL_RETURN_VAL_IF_FAIL (filename != NULL, NULL); _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, NULL); - return _cogl_bitmap_from_file (filename, error); + return _cogl_bitmap_from_file (ctx, filename, error); } CoglBitmap * @@ -293,6 +295,22 @@ cogl_bitmap_new_with_size (CoglContext *context, return bitmap; } +#ifdef COGL_HAS_ANDROID_SUPPORT +CoglBitmap * +cogl_android_bitmap_new_from_asset (CoglContext *ctx, + AAssetManager *manager, + const char *filename, + GError **error) +{ + _COGL_RETURN_VAL_IF_FAIL (ctx != NULL, NULL); + _COGL_RETURN_VAL_IF_FAIL (manager != NULL, NULL); + _COGL_RETURN_VAL_IF_FAIL (filename != NULL, NULL); + _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, NULL); + + return _cogl_android_bitmap_new_from_asset (ctx, manager, filename, error); +} +#endif + CoglPixelFormat cogl_bitmap_get_format (CoglBitmap *bitmap) { diff --git a/cogl/cogl-bitmap.h b/cogl/cogl-bitmap.h index 5f5674a5..574f5080 100644 --- a/cogl/cogl-bitmap.h +++ b/cogl/cogl-bitmap.h @@ -33,6 +33,10 @@ #include #include +#ifdef COGL_HAS_ANDROID_SUPPORT +#include +#endif + G_BEGIN_DECLS typedef struct _CoglBitmap CoglBitmap; @@ -50,6 +54,7 @@ typedef struct _CoglBitmap CoglBitmap; /** * cogl_bitmap_new_from_file: + * @context: A #CoglContext * @filename: the file to load. * @error: a #GError or %NULL. * @@ -62,9 +67,32 @@ typedef struct _CoglBitmap CoglBitmap; * Since: 1.0 */ CoglBitmap * -cogl_bitmap_new_from_file (const char *filename, +cogl_bitmap_new_from_file (CoglContext *context, + const char *filename, GError **error); +#ifdef COGL_HAS_ANDROID_SUPPORT +/** + * cogl_android_bitmap_new_from_asset: + * @context: A #CoglContext + * @manager: An Android Asset Manager. + * @filename: The file name for the asset + * @error: A return location for a GError exception. + * + * Loads an Android asset into a newly allocated #CoglBitmap. + * + * Return value: A newly allocated #CoglBitmap holding the image data of the + * specified asset. + * + * Since: 2.0 + */ +CoglBitmap * +cogl_android_bitmap_new_from_asset (CoglContext *context, + AAssetManager *manager, + const char *filename, + GError **error); +#endif + #if defined (COGL_ENABLE_EXPERIMENTAL_API) /** diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c index d01072e8..e5fdc709 100644 --- a/cogl/cogl-texture.c +++ b/cogl/cogl-texture.c @@ -450,9 +450,11 @@ cogl_texture_new_from_file (const char *filename, CoglTexture *texture = NULL; CoglPixelFormat src_format; + _COGL_GET_CONTEXT (ctx, NULL); + _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, NULL); - bmp = cogl_bitmap_new_from_file (filename, error); + bmp = cogl_bitmap_new_from_file (ctx, filename, error); if (bmp == NULL) return NULL; -- cgit v1.2.1