2007-07-24 Emmanuele Bassi <ebassi@openedhand.com>

* clutter/clutter-texture.[ch]: Add a ClutterTextureError
	to be returned by the loader functions; use the GObject API
	to allocate the private data structure instead of managing it
	ourselves; add documentation.
This commit is contained in:
Emmanuele Bassi 2007-07-24 17:38:35 +00:00
parent a37f537cd0
commit a87ede2e12
3 changed files with 112 additions and 80 deletions

View File

@ -1,3 +1,10 @@
2007-07-24 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-texture.[ch]: Add a ClutterTextureError
to be returned by the loader functions; use the GObject API
to allocate the private data structure instead of managing it
ourselves; add documentation.
2007-07-24 Emmanuele Bassi <ebassi@openedhand.com> 2007-07-24 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-actor.c: * clutter/clutter-actor.c:

View File

@ -30,12 +30,12 @@
* #ClutterTexture is a base class for displaying and manipulating pixel * #ClutterTexture is a base class for displaying and manipulating pixel
* buffer type data. * buffer type data.
* *
* The #clutter_texture_set_from_rgb_data and #clutter_texture_set_pixbuf are * The clutter_texture_set_from_rgb_data() and clutter_texture_set_pixbuf()
* used to copy image data into texture memory and subsequently realize the * functions are used to copy image data into texture memory and subsequently
* the texture. * realize the the texture.
* *
* If texture reads are supported by underlying GL implementaion * If texture reads are supported by underlying GL implementation,
* Unrealizing/hiding frees image data from texture memory moving to main * unrealizing/hiding frees image data from texture memory moving to main
* system memory. Re-realizing then performs the opposite operation. * system memory. Re-realizing then performs the opposite operation.
* This process allows basic management of commonly limited available texture * This process allows basic management of commonly limited available texture
* memory. * memory.
@ -68,6 +68,8 @@ typedef struct {
gint waste; gint waste;
} ClutterTextureTileDimension; } ClutterTextureTileDimension;
#define CLUTTER_TEXTURE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_TEXTURE, ClutterTexturePrivate))
struct _ClutterTexturePrivate struct _ClutterTexturePrivate
{ {
gint width; gint width;
@ -112,6 +114,12 @@ enum
static int texture_signals[LAST_SIGNAL] = { 0 }; static int texture_signals[LAST_SIGNAL] = { 0 };
GQuark
clutter_texture_error_quark (void)
{
return g_quark_from_static_string ("clutter-texture-error-quark");
}
static guchar* static guchar*
un_pre_multiply_alpha (const guchar *data, un_pre_multiply_alpha (const guchar *data,
gint width, gint width,
@ -260,7 +268,7 @@ texture_init_tiles (ClutterTexture *texture)
} }
if (priv->x_tiles) if (priv->x_tiles)
g_free(priv->x_tiles); g_free (priv->x_tiles);
priv->n_x_tiles = tile_dimension (priv->width, x_pot, priv->n_x_tiles = tile_dimension (priv->width, x_pot,
priv->max_tile_waste, NULL); priv->max_tile_waste, NULL);
@ -268,7 +276,7 @@ texture_init_tiles (ClutterTexture *texture)
tile_dimension (priv->width, x_pot, priv->max_tile_waste, priv->x_tiles); tile_dimension (priv->width, x_pot, priv->max_tile_waste, priv->x_tiles);
if (priv->y_tiles) if (priv->y_tiles)
g_free(priv->y_tiles); g_free (priv->y_tiles);
priv->n_y_tiles = tile_dimension (priv->height, y_pot, priv->n_y_tiles = tile_dimension (priv->height, y_pot,
priv->max_tile_waste, NULL); priv->max_tile_waste, NULL);
@ -387,19 +395,19 @@ texture_free_gl_resources (ClutterTexture *texture)
else else
cogl_textures_destroy (priv->n_x_tiles * priv->n_y_tiles, priv->tiles); cogl_textures_destroy (priv->n_x_tiles * priv->n_y_tiles, priv->tiles);
g_free(priv->tiles); g_free (priv->tiles);
priv->tiles = NULL; priv->tiles = NULL;
} }
if (priv->x_tiles) if (priv->x_tiles)
{ {
g_free(priv->x_tiles); g_free (priv->x_tiles);
priv->x_tiles = NULL; priv->x_tiles = NULL;
} }
if (priv->y_tiles) if (priv->y_tiles)
{ {
g_free(priv->y_tiles); g_free (priv->y_tiles);
priv->y_tiles = NULL; priv->y_tiles = NULL;
} }
} }
@ -758,34 +766,17 @@ clutter_texture_dispose (GObject *object)
priv = texture->priv; priv = texture->priv;
if (priv != NULL) texture_free_gl_resources (texture);
{
texture_free_gl_resources (texture);
if (priv->local_pixbuf != NULL) if (priv->local_pixbuf != NULL)
{ {
g_object_unref (priv->local_pixbuf); g_object_unref (priv->local_pixbuf);
priv->local_pixbuf = NULL; priv->local_pixbuf = NULL;
}
} }
G_OBJECT_CLASS (clutter_texture_parent_class)->dispose (object); G_OBJECT_CLASS (clutter_texture_parent_class)->dispose (object);
} }
static void
clutter_texture_finalize (GObject *object)
{
ClutterTexture *self = CLUTTER_TEXTURE(object);
if (self->priv)
{
g_free(self->priv);
self->priv = NULL;
}
G_OBJECT_CLASS (clutter_texture_parent_class)->finalize (object);
}
static void static void
clutter_texture_set_property (GObject *object, clutter_texture_set_property (GObject *object,
guint prop_id, guint prop_id,
@ -893,8 +884,10 @@ clutter_texture_class_init (ClutterTextureClass *klass)
GObjectClass *gobject_class; GObjectClass *gobject_class;
ClutterActorClass *actor_class; ClutterActorClass *actor_class;
gobject_class = (GObjectClass*)klass; gobject_class = (GObjectClass*) klass;
actor_class = (ClutterActorClass*)klass; actor_class = (ClutterActorClass*) klass;
g_type_class_add_private (klass, sizeof (ClutterTexturePrivate));
actor_class->paint = clutter_texture_paint; actor_class->paint = clutter_texture_paint;
actor_class->realize = clutter_texture_realize; actor_class->realize = clutter_texture_realize;
@ -903,7 +896,6 @@ clutter_texture_class_init (ClutterTextureClass *klass)
actor_class->hide = clutter_texture_hide; actor_class->hide = clutter_texture_hide;
gobject_class->dispose = clutter_texture_dispose; gobject_class->dispose = clutter_texture_dispose;
gobject_class->finalize = clutter_texture_finalize;
gobject_class->set_property = clutter_texture_set_property; gobject_class->set_property = clutter_texture_set_property;
gobject_class->get_property = clutter_texture_get_property; gobject_class->get_property = clutter_texture_get_property;
@ -1045,7 +1037,7 @@ clutter_texture_init (ClutterTexture *self)
{ {
ClutterTexturePrivate *priv; ClutterTexturePrivate *priv;
priv = g_new0 (ClutterTexturePrivate, 1); self->priv = priv = CLUTTER_TEXTURE_GET_PRIVATE (self);
priv->max_tile_waste = 64; priv->max_tile_waste = 64;
priv->filter_quality = 0; priv->filter_quality = 0;
@ -1062,8 +1054,6 @@ clutter_texture_init (ClutterTexture *self)
} }
else else
priv->target_type = CGL_TEXTURE_2D; priv->target_type = CGL_TEXTURE_2D;
self->priv = priv;
} }
static void static void
@ -1253,11 +1243,12 @@ clutter_texture_set_from_rgb_data (ClutterTexture *texture,
priv = texture->priv; priv = texture->priv;
g_return_val_if_fail (data != NULL, FALSE); g_return_val_if_fail (data != NULL, FALSE);
/* Needed for GL_RGBA (internal format) and gdk pixbuf usage */ /* Needed for GL_RGBA (internal format) and gdk pixbuf usage */
g_return_val_if_fail (bpp == 4, FALSE); g_return_val_if_fail (bpp == 4, FALSE);
texture_dirty = size_change = (width != priv->width texture_dirty = size_change =
|| height != priv->height); (width != priv->width || height != priv->height);
prev_format = priv->pixel_format; prev_format = priv->pixel_format;
@ -1295,12 +1286,12 @@ clutter_texture_set_from_rgb_data (ClutterTexture *texture,
if (priv->is_tiled == FALSE) if (priv->is_tiled == FALSE)
{ {
if (priv->target_type == CGL_TEXTURE_RECTANGLE_ARB if (priv->target_type == CGL_TEXTURE_RECTANGLE_ARB &&
&& !cogl_texture_can_size (CGL_TEXTURE_RECTANGLE_ARB, !cogl_texture_can_size (CGL_TEXTURE_RECTANGLE_ARB,
priv->pixel_format, priv->pixel_format,
priv->pixel_type, priv->pixel_type,
priv->width, priv->width,
priv->height)) priv->height))
{ {
/* If we cant create NPOT tex of this size fall back to tiles */ /* If we cant create NPOT tex of this size fall back to tiles */
CLUTTER_NOTE (TEXTURE, CLUTTER_NOTE (TEXTURE,
@ -1312,12 +1303,12 @@ clutter_texture_set_from_rgb_data (ClutterTexture *texture,
priv->target_type = CGL_TEXTURE_2D; priv->target_type = CGL_TEXTURE_2D;
} }
if (priv->target_type == CGL_TEXTURE_2D if (priv->target_type == CGL_TEXTURE_2D &&
&& !cogl_texture_can_size (CGL_TEXTURE_2D, !cogl_texture_can_size (CGL_TEXTURE_2D,
priv->pixel_format, priv->pixel_format,
priv->pixel_type, priv->pixel_type,
clutter_util_next_p2(priv->width), clutter_util_next_p2 (priv->width),
clutter_util_next_p2(priv->height))) clutter_util_next_p2 (priv->height)))
{ {
priv->is_tiled = TRUE; priv->is_tiled = TRUE;
} }
@ -1374,13 +1365,16 @@ clutter_texture_set_from_rgb_data (ClutterTexture *texture,
* @width: Width in pixels of image data. * @width: Width in pixels of image data.
* @height: Height in pixels of image data * @height: Height in pixels of image data
* @flags: #ClutterTextureFlags * @flags: #ClutterTextureFlags
* @error: FIXME. * @error: Return location for a #GError, or %NULL.
* *
* Sets a #ClutterTexture from YUV image data. * Sets a #ClutterTexture from YUV image data. If an error occurred,
* %FALSE is returned and @error is set.
* *
* Return value: TRUE on success, FALSE on failure. * This function is likely to change in future versions.
* *
* Since 0.4. This function is likely to change in future versions. * Return value: %TRUE if the texture was successfully updated
*
* Since 0.4.
**/ **/
gboolean gboolean
clutter_texture_set_from_yuv_data (ClutterTexture *texture, clutter_texture_set_from_yuv_data (ClutterTexture *texture,
@ -1393,8 +1387,15 @@ clutter_texture_set_from_yuv_data (ClutterTexture *texture,
ClutterTexturePrivate *priv; ClutterTexturePrivate *priv;
gboolean texture_dirty = TRUE, size_change = FALSE; gboolean texture_dirty = TRUE, size_change = FALSE;
if (!clutter_feature_available(CLUTTER_FEATURE_TEXTURE_YUV)) g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), FALSE);
return FALSE;
if (!clutter_feature_available (CLUTTER_FEATURE_TEXTURE_YUV))
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_NO_YUV,
"YUV textures are not supported");
return FALSE;
}
priv = texture->priv; priv = texture->priv;
@ -1427,26 +1428,37 @@ clutter_texture_set_from_yuv_data (ClutterTexture *texture,
if (texture_dirty) if (texture_dirty)
{ {
gint new_width, new_height;
new_width = clutter_util_next_p2 (priv->width);
new_height = clutter_util_next_p2 (priv->height);
/* FIXME: need to check size limits correctly - does not /* FIXME: need to check size limits correctly - does not
* seem to work if correct format and typre are used so * seem to work if correct format and type are used so
* this is really a guess... * this is really a guess...
*/ */
if (cogl_texture_can_size (CGL_TEXTURE_2D, if (cogl_texture_can_size (CGL_TEXTURE_2D,
CGL_RGBA, CGL_RGBA,
CGL_UNSIGNED_BYTE, CGL_UNSIGNED_BYTE,
clutter_util_next_p2(priv->width), new_width, new_height))
clutter_util_next_p2(priv->height)))
{ {
cogl_texture_image_2d (priv->target_type, cogl_texture_image_2d (priv->target_type,
priv->pixel_format, priv->pixel_format,
clutter_util_next_p2(priv->width), new_width, new_height,
clutter_util_next_p2(priv->height), priv->pixel_format,
priv->pixel_format,
priv->pixel_type, priv->pixel_type,
NULL); NULL);
} }
else else
return FALSE; /* FIXME: add tiling */ {
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_OUT_OF_MEMORY,
"Unable to allocate a texture of %d by %d pixels",
new_width,
new_height);
return FALSE; /* FIXME: add tiling */
}
} }
cogl_texture_sub_image_2d (priv->target_type, cogl_texture_sub_image_2d (priv->target_type,
@ -1483,10 +1495,15 @@ clutter_texture_set_from_yuv_data (ClutterTexture *texture,
* clutter_texture_set_pixbuf: * clutter_texture_set_pixbuf:
* @texture: A #ClutterTexture * @texture: A #ClutterTexture
* @pixbuf: A #GdkPixbuf * @pixbuf: A #GdkPixbuf
* @error: Return location for a #GError, or %NULL
* *
* Sets a #ClutterTexture image data from a #GdkPixbuf * Sets a #ClutterTexture image data from a #GdkPixbuf. In case of
* failure, %FALSE is returned and @error is set.
* *
**/ * Return value: %TRUE if the pixbuf was successfully set
*
* Since: 0.4
*/
gboolean gboolean
clutter_texture_set_pixbuf (ClutterTexture *texture, clutter_texture_set_pixbuf (ClutterTexture *texture,
GdkPixbuf *pixbuf, GdkPixbuf *pixbuf,

View File

@ -38,6 +38,14 @@ G_BEGIN_DECLS
#define CLUTTER_IS_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_TEXTURE)) #define CLUTTER_IS_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_TEXTURE))
#define CLUTTER_TEXTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_TEXTURE, ClutterTextureClass)) #define CLUTTER_TEXTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_TEXTURE, ClutterTextureClass))
typedef enum {
CLUTTER_TEXTURE_ERROR_OUT_OF_MEMORY,
CLUTTER_TEXTURE_ERROR_NO_YUV
} ClutterTextureError;
#define CLUTTER_TEXTURE_ERROR (clutter_texture_error_quark ())
GQuark clutter_texture_error_quark (void);
typedef struct _ClutterTexture ClutterTexture; typedef struct _ClutterTexture ClutterTexture;
typedef struct _ClutterTextureClass ClutterTextureClass; typedef struct _ClutterTextureClass ClutterTextureClass;
typedef struct _ClutterTexturePrivate ClutterTexturePrivate; typedef struct _ClutterTexturePrivate ClutterTexturePrivate;
@ -69,16 +77,16 @@ struct _ClutterTextureClass
typedef enum ClutterTextureFlags typedef enum ClutterTextureFlags
{ {
CLUTTER_TEXTURE_RGB_FLAG_BGR = (1<<1), CLUTTER_TEXTURE_RGB_FLAG_BGR = (1 << 1),
CLUTTER_TEXTURE_RGB_FLAG_PREMULT = (1<<2), /* FIXME: not handled */ CLUTTER_TEXTURE_RGB_FLAG_PREMULT = (1 << 2), /* FIXME: not handled */
CLUTTER_TEXTURE_YUV_FLAG_YUV2 = (1<<3) CLUTTER_TEXTURE_YUV_FLAG_YUV2 = (1 << 3)
/* FIXME: add compressed types ? */ /* FIXME: add compressed types ? */
} ClutterTextureFlags; } ClutterTextureFlags;
GType clutter_texture_get_type (void) G_GNUC_CONST; GType clutter_texture_get_type (void) G_GNUC_CONST;
ClutterActor *clutter_texture_new (void); ClutterActor *clutter_texture_new (void);
ClutterActor *clutter_texture_new_from_pixbuf (GdkPixbuf *pixbuf); ClutterActor *clutter_texture_new_from_pixbuf (GdkPixbuf *pixbuf);
gboolean clutter_texture_set_from_rgb_data (ClutterTexture *texture, gboolean clutter_texture_set_from_rgb_data (ClutterTexture *texture,
const guchar *data, const guchar *data,
gboolean has_alpha, gboolean has_alpha,
@ -97,24 +105,24 @@ gboolean clutter_texture_set_from_yuv_data (ClutterTexture *texture,
gboolean clutter_texture_set_pixbuf (ClutterTexture *texture, gboolean clutter_texture_set_pixbuf (ClutterTexture *texture,
GdkPixbuf *pixbuf, GdkPixbuf *pixbuf,
GError **error); GError **error);
GdkPixbuf * clutter_texture_get_pixbuf (ClutterTexture *texture); GdkPixbuf * clutter_texture_get_pixbuf (ClutterTexture *texture);
void clutter_texture_get_base_size (ClutterTexture *texture, void clutter_texture_get_base_size (ClutterTexture *texture,
gint *width, gint *width,
gint *height); gint *height);
/* Below mainly for subclassed texture based actors */ /* Below mainly for subclassed texture based actors */
void clutter_texture_bind_tile (ClutterTexture *texture, void clutter_texture_bind_tile (ClutterTexture *texture,
gint index); gint index);
void clutter_texture_get_n_tiles (ClutterTexture *texture, void clutter_texture_get_n_tiles (ClutterTexture *texture,
gint *n_x_tiles, gint *n_x_tiles,
gint *n_y_tiles); gint *n_y_tiles);
void clutter_texture_get_x_tile_detail (ClutterTexture *texture, void clutter_texture_get_x_tile_detail (ClutterTexture *texture,
gint x_index, gint x_index,
gint *pos, gint *pos,
gint *size, gint *size,
gint *waste); gint *waste);
void clutter_texture_get_y_tile_detail (ClutterTexture *texture, void clutter_texture_get_y_tile_detail (ClutterTexture *texture,
gint y_index, gint y_index,
gint *pos, gint *pos,
gint *size, gint *size,