2006-09-19 Matthew Allum <mallum@openedhand.com>

* clutter/clutter-actor.c: (redraw_update_idle),
        (clutter_actor_queue_redraw):
        * clutter/clutter-main.c: (clutter_redraw):
        Remove now uneeded locks
        ( new gst and texture code makes redundant )

        * clutter/clutter-texture.c:
        * clutter/clutter-texture.h:
        Redo clutter texture as to not keep a reference
        to underlying texture.
This commit is contained in:
Matthew Allum 2006-09-19 19:27:16 +00:00
parent 55c723b9a2
commit 94c0e54bc3
5 changed files with 350 additions and 206 deletions

View File

@ -1,3 +1,16 @@
2006-09-19 Matthew Allum <mallum@openedhand.com>
* clutter/clutter-actor.c: (redraw_update_idle),
(clutter_actor_queue_redraw):
* clutter/clutter-main.c: (clutter_redraw):
Remove now uneeded locks
( new gst and texture code makes redundant )
* clutter/clutter-texture.c:
* clutter/clutter-texture.h:
Redo clutter texture as to not keep a reference
to underlying texture.
2006-09-15 Matthew Allum <mallum@openedhand.com> 2006-09-15 Matthew Allum <mallum@openedhand.com>
More fixes from Bastien Nocera (#155): More fixes from Bastien Nocera (#155):

View File

@ -100,16 +100,12 @@ redraw_update_idle (gpointer data)
{ {
ClutterMainContext *ctx = CLUTTER_CONTEXT(); ClutterMainContext *ctx = CLUTTER_CONTEXT();
clutter_threads_enter();
if (ctx->update_idle) if (ctx->update_idle)
{ {
g_source_remove (ctx->update_idle); g_source_remove (ctx->update_idle);
ctx->update_idle = 0; ctx->update_idle = 0;
} }
clutter_threads_leave();
clutter_redraw (); clutter_redraw ();
return FALSE; return FALSE;
@ -764,16 +760,12 @@ clutter_actor_queue_redraw (ClutterActor *self)
{ {
ClutterMainContext *ctx = CLUTTER_CONTEXT(); ClutterMainContext *ctx = CLUTTER_CONTEXT();
clutter_threads_enter();
if (!ctx->update_idle) if (!ctx->update_idle)
{ {
ctx->update_idle = g_idle_add_full (-100 , /* very high priority */ ctx->update_idle = g_idle_add_full (-100 , /* very high priority */
redraw_update_idle, redraw_update_idle,
NULL, NULL); NULL, NULL);
} }
clutter_threads_leave();
} }
/** /**

View File

@ -269,8 +269,6 @@ clutter_redraw (void)
CLUTTER_DBG("@@@ Redraw enter @@@"); CLUTTER_DBG("@@@ Redraw enter @@@");
clutter_threads_enter ();
if (clutter_want_fps ()) if (clutter_want_fps ())
{ {
if (!timer) if (!timer)
@ -319,8 +317,6 @@ clutter_redraw (void)
} }
} }
clutter_threads_leave ();
CLUTTER_DBG("@@@ Redraw leave @@@"); CLUTTER_DBG("@@@ Redraw leave @@@");
} }

View File

@ -29,6 +29,13 @@
* *
* #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_data and #clutter_texture_set_pixbuf are
* used to copy image data into texture memory and subsequently realize the
* the texture. Unrealizing/hiding frees image data from texture memory moving
* to main system memory. Re-realizing then performs the opposite operation.
* This process allows basic management of commonly limited available texture
* memory.
*/ */
#include "clutter-texture.h" #include "clutter-texture.h"
@ -57,12 +64,13 @@ ClutterTextureTileDimention;
struct ClutterTexturePrivate struct ClutterTexturePrivate
{ {
GdkPixbuf *pixbuf;
gint width, height; gint width, height;
GLenum pixel_format; GLenum pixel_format;
GLenum pixel_type; GLenum pixel_type;
GLenum target_type; GLenum target_type;
GdkPixbuf *local_pixbuf; /* non video memory copy */
gboolean sync_actor_size; gboolean sync_actor_size;
gint max_tile_waste; gint max_tile_waste;
guint filter_quality; guint filter_quality;
@ -73,7 +81,6 @@ struct ClutterTexturePrivate
ClutterTextureTileDimention *x_tiles, *y_tiles; ClutterTextureTileDimention *x_tiles, *y_tiles;
gint n_x_tiles, n_y_tiles; gint n_x_tiles, n_y_tiles;
GLuint *tiles; GLuint *tiles;
}; };
enum enum
@ -99,9 +106,6 @@ enum
static int texture_signals[LAST_SIGNAL] = { 0 }; static int texture_signals[LAST_SIGNAL] = { 0 };
static void
init_tiles (ClutterTexture *texture);
static gboolean static gboolean
can_create (int width, can_create (int width,
int height, int height,
@ -176,7 +180,7 @@ tile_dimension (int to_fill,
} }
static void static void
init_tiles (ClutterTexture *texture) texture_init_tiles (ClutterTexture *texture)
{ {
ClutterTexturePrivate *priv; ClutterTexturePrivate *priv;
gint x_pot, y_pot; gint x_pot, y_pot;
@ -325,33 +329,21 @@ texture_render_to_gl_quad (ClutterTexture *texture,
} }
static void static void
clutter_texture_unrealize (ClutterActor *actor) texture_free_gl_resources (ClutterTexture *texture)
{ {
ClutterTexture *texture;
ClutterTexturePrivate *priv; ClutterTexturePrivate *priv;
texture = CLUTTER_TEXTURE(actor);
priv = texture->priv; priv = texture->priv;
if (priv->tiles == NULL)
return;
CLUTTER_MARK();
clutter_threads_enter ();
/* Free up texture memory */
if (!priv->tiled)
glDeleteTextures(1, priv->tiles);
else
glDeleteTextures(priv->n_x_tiles * priv->n_y_tiles, priv->tiles);
clutter_threads_leave ();
CLUTTER_MARK(); CLUTTER_MARK();
if (priv->tiles) if (priv->tiles)
{ {
if (!priv->tiled)
glDeleteTextures(1, priv->tiles);
else
glDeleteTextures(priv->n_x_tiles * priv->n_y_tiles, priv->tiles);
g_free(priv->tiles); g_free(priv->tiles);
priv->tiles = NULL; priv->tiles = NULL;
} }
@ -367,12 +359,16 @@ clutter_texture_unrealize (ClutterActor *actor)
g_free(priv->y_tiles); g_free(priv->y_tiles);
priv->y_tiles = NULL; priv->y_tiles = NULL;
} }
CLUTTER_DBG("Texture unrealized");
} }
static void static void
clutter_texture_sync_pixbuf (ClutterTexture *texture) texture_upload_data (ClutterTexture *texture,
const guchar *data,
gboolean has_alpha,
gint width,
gint height,
gint rowstride,
gint bpp)
{ {
ClutterTexturePrivate *priv; ClutterTexturePrivate *priv;
int x, y, i = 0; int x, y, i = 0;
@ -380,15 +376,13 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
priv = texture->priv; priv = texture->priv;
g_return_if_fail (priv->pixbuf != NULL); g_return_if_fail (data != NULL);
CLUTTER_MARK(); CLUTTER_MARK();
if (!priv->tiled) if (!priv->tiled)
{ {
/* Single Texture /* Single Texture */
*
*/
if (!priv->tiles) if (!priv->tiles)
{ {
priv->tiles = g_new (GLuint, 1); priv->tiles = g_new (GLuint, 1);
@ -416,10 +410,8 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
glTexParameteri(priv->target_type, GL_TEXTURE_MIN_FILTER, glTexParameteri(priv->target_type, GL_TEXTURE_MIN_FILTER,
priv->filter_quality ? GL_LINEAR : GL_NEAREST); priv->filter_quality ? GL_LINEAR : GL_NEAREST);
glPixelStorei (GL_UNPACK_ROW_LENGTH, glPixelStorei (GL_UNPACK_ROW_LENGTH, priv->width);
gdk_pixbuf_get_width(priv->pixbuf)); glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
glPixelStorei (GL_UNPACK_ALIGNMENT,
gdk_pixbuf_get_n_channels (priv->pixbuf));
if (create_textures) if (create_textures)
{ {
@ -434,11 +426,10 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
height = clutter_util_next_p2(priv->height); height = clutter_util_next_p2(priv->height);
} }
/* NOTE: Change to GL_RGB for non alpha textures */
glTexImage2D(priv->target_type, glTexImage2D(priv->target_type,
0, 0,
(gdk_pixbuf_get_n_channels (priv->pixbuf) == 4) ? /* (has_alpha) ? GL_RGBA : GL_RGB, */
GL_RGBA : GL_RGB, GL_RGBA,
width, width,
height, height,
0, 0,
@ -452,8 +443,7 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
priv->height, priv->height,
priv->pixel_format, priv->pixel_format,
priv->pixel_type, priv->pixel_type,
gdk_pixbuf_get_pixels(priv->pixbuf)); data);
return; return;
} }
@ -474,19 +464,15 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
for (x=0; x < priv->n_x_tiles; x++) for (x=0; x < priv->n_x_tiles; x++)
for (y=0; y < priv->n_y_tiles; y++) for (y=0; y < priv->n_y_tiles; y++)
{ {
GdkPixbuf *pixtmp; guchar *tmp;
int src_h, src_w; gint src_h, src_w, dy;
src_w = priv->x_tiles[x].size; src_w = priv->x_tiles[x].size;
src_h = priv->y_tiles[y].size; src_h = priv->y_tiles[y].size;
pixtmp /* fixme - gslice ? */
= gdk_pixbuf_new(GDK_COLORSPACE_RGB, tmp = g_malloc (sizeof(guchar) * priv->x_tiles[x].size
(gdk_pixbuf_get_n_channels (priv->pixbuf) == 4) ? * priv->y_tiles[y].size * bpp);
TRUE : FALSE,
8,
priv->x_tiles[x].size,
priv->y_tiles[y].size);
/* clip */ /* clip */
if (priv->x_tiles[x].pos + src_w > priv->width) if (priv->x_tiles[x].pos + src_w > priv->width)
@ -507,13 +493,13 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
priv->x_tiles[x].size, priv->x_tiles[x].size,
priv->y_tiles[y].size); priv->y_tiles[y].size);
gdk_pixbuf_copy_area(priv->pixbuf, for (dy = 0; dy < src_h; dy++)
priv->x_tiles[x].pos, {
priv->y_tiles[y].pos, memcpy (tmp + (dy * src_w * bpp),
src_w, data + ((priv->y_tiles[y].pos + dy) * rowstride)
src_h, + (priv->x_tiles[x].pos * bpp),
pixtmp, (src_w * bpp));
0,0); }
#ifdef CLUTTER_DUMP_TILES #ifdef CLUTTER_DUMP_TILES
{ {
@ -545,23 +531,22 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glPixelStorei (GL_UNPACK_ROW_LENGTH, gdk_pixbuf_get_width(pixtmp)); glPixelStorei (GL_UNPACK_ROW_LENGTH, priv->width);
glPixelStorei (GL_UNPACK_ALIGNMENT, glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
gdk_pixbuf_get_n_channels (priv->pixbuf));
if (create_textures) if (create_textures)
{ {
glTexImage2D(priv->target_type, glTexImage2D(priv->target_type,
0, 0,
(gdk_pixbuf_get_n_channels (priv->pixbuf) == 4) ? (bpp == 4) ?
GL_RGBA : GL_RGB, GL_RGBA : GL_RGB,
priv->x_tiles[x].size, priv->x_tiles[x].size,
priv->y_tiles[y].size, priv->y_tiles[y].size,
0, 0,
priv->pixel_format, priv->pixel_format,
priv->pixel_type, priv->pixel_type,
gdk_pixbuf_get_pixels(pixtmp)); tmp);
} }
else else
{ {
@ -573,39 +558,72 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
priv->y_tiles[y].size, priv->y_tiles[y].size,
priv->pixel_format, priv->pixel_format,
priv->pixel_type, priv->pixel_type,
gdk_pixbuf_get_pixels(pixtmp)); tmp);
} }
g_object_unref(pixtmp); g_free(tmp);
i++; i++;
} }
} }
static void static void
clutter_texture_realize (ClutterActor *actor) clutter_texture_unrealize (ClutterActor *actor)
{ {
ClutterTexture *texture; ClutterTexture *texture;
ClutterTexturePrivate *priv;
texture = CLUTTER_TEXTURE(actor); texture = CLUTTER_TEXTURE(actor);
priv = texture->priv;
if (priv->tiles == NULL)
return;
CLUTTER_MARK(); CLUTTER_MARK();
if (texture->priv->pixbuf == NULL) /* Move image data from video to main memory
*/
if (priv->local_pixbuf == NULL)
priv->local_pixbuf = clutter_texture_get_pixbuf (texture);
texture_free_gl_resources (texture);
CLUTTER_DBG("Texture unrealized");
}
static void
clutter_texture_realize (ClutterActor *actor)
{ {
/* Dont allow realization with no pixbuf */ ClutterTexture *texture;
CLUTTER_DBG("*** Texture has no pixbuf cannot realize ***"); ClutterTexturePrivate *priv;
texture = CLUTTER_TEXTURE(actor);
priv = texture->priv;
CLUTTER_MARK();
if (priv->local_pixbuf != NULL)
{
/* Move any local image data we have from unrealization
* back into video memory.
*/
clutter_texture_set_pixbuf (texture, priv->local_pixbuf);
g_object_unref (priv->local_pixbuf);
priv->local_pixbuf = NULL;
}
else
{
/* Dont allow realization with no pixbuf - note set_pixbuf/data
* will set realize flags.
*/
CLUTTER_DBG("*** Texture has no image data cannot realize ***");
CLUTTER_DBG("*** flags %i ***", actor->flags); CLUTTER_DBG("*** flags %i ***", actor->flags);
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
CLUTTER_DBG("*** flags %i ***", actor->flags); CLUTTER_DBG("*** flags %i ***", actor->flags);
return; return;
} }
CLUTTER_DBG("Texture realized"); CLUTTER_DBG("Texture realized");
if (texture->priv->tiled)
init_tiles(texture);
clutter_texture_sync_pixbuf (texture);
} }
static void static void
@ -653,19 +671,19 @@ clutter_texture_paint (ClutterActor *self)
static void static void
clutter_texture_dispose (GObject *object) clutter_texture_dispose (GObject *object)
{ {
ClutterTexture *self = CLUTTER_TEXTURE(object); ClutterTexture *texture = CLUTTER_TEXTURE(object);
ClutterTexturePrivate *priv; ClutterTexturePrivate *priv;
priv = self->priv; priv = texture->priv;
if (priv != NULL) if (priv != NULL)
{ {
clutter_actor_unrealize (CLUTTER_ACTOR(self)); texture_free_gl_resources (texture);
if (priv->pixbuf != NULL) if (priv->local_pixbuf != NULL)
{ {
g_object_unref (priv->pixbuf); g_object_unref (priv->local_pixbuf);
priv->pixbuf = NULL; priv->local_pixbuf = NULL;
} }
} }
@ -755,7 +773,11 @@ clutter_texture_get_property (GObject *object,
switch (prop_id) switch (prop_id)
{ {
case PROP_PIXBUF: case PROP_PIXBUF:
g_value_set_pointer (value, priv->pixbuf); {
GdkPixbuf *pixb;
pixb = clutter_texture_get_pixbuf (texture);
g_value_set_pointer (value, pixb);
}
break; break;
case PROP_USE_TILES: case PROP_USE_TILES:
g_value_set_boolean (value, priv->tiled); g_value_set_boolean (value, priv->tiled);
@ -932,12 +954,6 @@ clutter_texture_init (ClutterTexture *self)
priv = g_new0 (ClutterTexturePrivate, 1); priv = g_new0 (ClutterTexturePrivate, 1);
/* FIXME: It seems defaults via props do not get set
* on all props for sub classes ( ie labels ).
* Should they be ?
*
* Setting them here also to be sure + safe.
*/
priv->max_tile_waste = 64; priv->max_tile_waste = 64;
priv->filter_quality = 0; priv->filter_quality = 0;
priv->tiled = TRUE; priv->tiled = TRUE;
@ -945,7 +961,6 @@ clutter_texture_init (ClutterTexture *self)
priv->pixel_format = GL_RGBA; priv->pixel_format = GL_RGBA;
priv->repeat_x = FALSE; priv->repeat_x = FALSE;
priv->repeat_y = FALSE; priv->repeat_y = FALSE;
priv->pixbuf = NULL;
if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE)) if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE))
{ {
@ -958,90 +973,173 @@ clutter_texture_init (ClutterTexture *self)
self->priv = priv; self->priv = priv;
} }
static void
pixbuf_destroy_notify (guchar *pixels, gpointer data)
{
g_free (pixels);
}
/** /**
* clutter_texture_get_pixbuf: * clutter_texture_get_pixbuf:
* @texture: A #ClutterTexture * @texture: A #ClutterTexture
* *
* Gets the underlying #GdkPixbuf for the #ClutterTexture. * Gets a #GdkPixbuf representation of the #ClutterTexture data.
* The created #GdkPixbuf is not owned by the texture but the caller.
* *
* Return value: The underlying #GdkPixbuf * Return value: A #GdkPixbuf
**/ **/
GdkPixbuf* GdkPixbuf*
clutter_texture_get_pixbuf (ClutterTexture* texture) clutter_texture_get_pixbuf (ClutterTexture* texture)
{ {
return texture->priv->pixbuf; ClutterTexturePrivate *priv;
GdkPixbuf *pixbuf = NULL;
guchar *pixels = NULL;
priv = texture->priv;
if (priv->tiles == NULL)
return NULL;
if (!priv->tiled)
{
pixels = g_malloc (priv->width * priv->height * 4);
if (pixels == NULL)
return NULL;
glBindTexture(priv->target_type, priv->tiles[0]);
glPixelStorei (GL_UNPACK_ROW_LENGTH, priv->width);
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
/* read data from gl text and return as pixbuf */
glGetTexImage (priv->target_type,
0,
priv->pixel_format,
priv->pixel_type,
(GLvoid*)pixels);
pixbuf = gdk_pixbuf_new_from_data ((const guchar*)pixels,
GDK_COLORSPACE_RGB,
(priv->pixel_format == GL_RGBA),
8,
priv->width,
priv->height,
priv->width * 4,
pixbuf_destroy_notify,
NULL);
}
else
{
int x,y,i;
i = 0;
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
(priv->pixel_format == GL_RGBA),
8,
priv->width,
priv->height);
for (x=0; x < priv->n_x_tiles; x++)
for (y=0; y < priv->n_y_tiles; y++)
{
GdkPixbuf *tmp_pixb;
gint src_h, src_w;
src_w = priv->x_tiles[x].size;
src_h = priv->y_tiles[y].size;
pixels = g_malloc (src_w * src_h *4);
glBindTexture(priv->target_type, priv->tiles[i]);
glPixelStorei (GL_UNPACK_ROW_LENGTH, src_w);
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
glGetTexImage (priv->target_type,
0,
priv->pixel_format,
priv->pixel_type,
(GLvoid*)pixels);
tmp_pixb
= gdk_pixbuf_new_from_data ((const guchar*)pixels,
GDK_COLORSPACE_RGB,
(priv->pixel_format == GL_RGBA),
8,
src_w,
src_h,
src_w * 4,
pixbuf_destroy_notify,
NULL);
gdk_pixbuf_copy_area (tmp_pixb,
0,
0,
src_w,
src_h,
pixbuf,
priv->x_tiles[x].pos,
priv->x_tiles[y].pos);
g_object_unref (tmp_pixb);
i++;
}
}
return pixbuf;
} }
/** /**
* clutter_texture_set_pixbuf: * clutter_texture_set_from_data:
* @texture: A #ClutterTexture * @texture: A #ClutterTexture
* @pixbuf: A #GdkPixbuf * @data: Image data in RGB type colorspace.
* @has_alpha: Set to TRUE if image data has a alpha channel.
* @width: Width in pixels of image data.
* @height: Height in pixels of image data
* @rowstride: Distance in bytes between row starts.
* @bpp: bytes per pixel ( Currently only 4 supported )
* *
* Sets the underlying #GdkPixbuf for the #ClutterTexture * Sets #ClutterTexture image data.
* *
* Since 0.2. This function is likely to change in future versions.
**/ **/
void void
clutter_texture_set_pixbuf (ClutterTexture *texture, GdkPixbuf *pixbuf) clutter_texture_set_from_data (ClutterTexture *texture,
const guchar *data,
gboolean has_alpha,
gint width,
gint height,
gint rowstride,
gint bpp)
{ {
ClutterTexturePrivate *priv; ClutterTexturePrivate *priv;
gboolean texture_dirty = TRUE; gboolean texture_dirty = TRUE;
priv = texture->priv; priv = texture->priv;
g_return_if_fail (pixbuf != NULL); g_return_if_fail (data != NULL);
g_return_if_fail (bpp == 4);
if (priv->pixbuf != NULL) /* FIXME: check other image props */
{ texture_dirty = (width != priv->width || height != priv->height);
texture_dirty = (gdk_pixbuf_get_width (pixbuf)
!= gdk_pixbuf_get_width (priv->pixbuf)
||
gdk_pixbuf_get_height (pixbuf)
!= gdk_pixbuf_get_height (priv->pixbuf)
||
gdk_pixbuf_get_n_channels (pixbuf)
!= gdk_pixbuf_get_n_channels (priv->pixbuf));
g_object_unref(priv->pixbuf); priv->width = width;
priv->height = height;
if (has_alpha)
priv->pixel_format = GL_RGBA;
else
priv->pixel_format = GL_RGB;
/* If the actual pixbuf has changed size/format destroy
* existing textures ready for recreation. If
* size matches we can reuse.
*/
if (texture_dirty) if (texture_dirty)
{ {
clutter_actor_unrealize (CLUTTER_ACTOR(texture)); texture_free_gl_resources (texture);
}
else
{
/* If texture realised sync things for change */
if (CLUTTER_ACTOR_IS_REALIZED(CLUTTER_ACTOR(texture)))
{
priv->pixbuf = pixbuf;
/* FIXME: better locking stratergy if (priv->tiled == FALSE)
*/
clutter_threads_enter();
clutter_texture_sync_pixbuf (texture);
clutter_threads_leave();
}
}
}
clutter_threads_enter();
priv->pixbuf = pixbuf;
priv->width = gdk_pixbuf_get_width (pixbuf);
priv->height = gdk_pixbuf_get_height (pixbuf);
g_object_ref (pixbuf);
if (gdk_pixbuf_get_n_channels (pixbuf) == 3)
priv->pixel_format = GL_RGB;
else
priv->pixel_format = GL_RGBA;
/* Force tiling if pixbuf is too big for single texture */
if (priv->tiled == FALSE && texture_dirty)
{ {
if (priv->target_type == GL_TEXTURE_RECTANGLE_ARB if (priv->target_type == GL_TEXTURE_RECTANGLE_ARB
&& !can_create_rect_arb (priv->width, && !can_create_rect_arb (priv->width,
@ -1062,27 +1160,63 @@ clutter_texture_set_pixbuf (ClutterTexture *texture, GdkPixbuf *pixbuf)
priv->tiled = TRUE; priv->tiled = TRUE;
} }
} }
clutter_threads_leave();
/* Figure our tiling etc */
if (priv->tiled)
texture_init_tiles (texture);
}
CLUTTER_DBG("set size %ix%i\n", priv->width, priv->height);
texture_upload_data (texture, data, has_alpha,
width, height, rowstride, bpp);
CLUTTER_ACTOR_SET_FLAGS (CLUTTER_ACTOR(texture), CLUTTER_ACTOR_REALIZED);
if (texture_dirty)
{
g_signal_emit (texture, texture_signals[SIGNAL_SIZE_CHANGE],
0, priv->width, priv->height);
if (priv->sync_actor_size) if (priv->sync_actor_size)
clutter_actor_set_size (CLUTTER_ACTOR(texture), clutter_actor_set_size (CLUTTER_ACTOR(texture),
priv->width, priv->width,
priv->height); priv->height);
}
CLUTTER_DBG("set size %ix%i\n", priv->width, priv->height); /* rename signal */
if (texture_dirty)
g_signal_emit (texture, texture_signals[SIGNAL_SIZE_CHANGE],
0, priv->width, priv->height);
if (priv->tiled && texture_dirty)
init_tiles (texture);
g_signal_emit (texture, texture_signals[SIGNAL_PIXBUF_CHANGE], 0); g_signal_emit (texture, texture_signals[SIGNAL_PIXBUF_CHANGE], 0);
/* If resized actor may need resizing but paint() will do this */ /* If resized actor may need resizing but paint() will do this */
if (CLUTTER_ACTOR_IS_MAPPED (CLUTTER_ACTOR(texture))) if (CLUTTER_ACTOR_IS_MAPPED (CLUTTER_ACTOR(texture)))
clutter_actor_queue_redraw (CLUTTER_ACTOR(texture)); clutter_actor_queue_redraw (CLUTTER_ACTOR(texture));
}
/**
* clutter_texture_set_pixbuf:
* @texture: A #ClutterTexture
* @pixbuf: A #GdkPixbuf
*
* Sets a #ClutterTexture image data from a #GdkPixbuf
*
**/
void
clutter_texture_set_pixbuf (ClutterTexture *texture, GdkPixbuf *pixbuf)
{
ClutterTexturePrivate *priv;
priv = texture->priv;
g_return_if_fail (pixbuf != NULL);
clutter_texture_set_from_data (texture,
gdk_pixbuf_get_pixels (pixbuf),
gdk_pixbuf_get_has_alpha (pixbuf),
gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
gdk_pixbuf_get_rowstride (pixbuf),
4);
} }
/** /**
@ -1129,7 +1263,7 @@ clutter_texture_new (void)
* Gets the size in pixels of the untransformed underlying texture pixbuf data. * Gets the size in pixels of the untransformed underlying texture pixbuf data.
* *
**/ **/
void void /* FIXME: rename to get_image_size */
clutter_texture_get_base_size (ClutterTexture *texture, clutter_texture_get_base_size (ClutterTexture *texture,
gint *width, gint *width,
gint *height) gint *height)

View File

@ -81,6 +81,15 @@ ClutterActor *clutter_texture_new_from_pixbuf (GdkPixbuf *pixbuf);
ClutterActor *clutter_texture_new (void); ClutterActor *clutter_texture_new (void);
void
clutter_texture_set_from_data (ClutterTexture *texture,
const guchar *data,
gboolean has_alpha,
gint width,
gint height,
gint rowstride,
gint bpp);
void clutter_texture_set_pixbuf (ClutterTexture *texture, GdkPixbuf *pixbuf); void clutter_texture_set_pixbuf (ClutterTexture *texture, GdkPixbuf *pixbuf);
GdkPixbuf *clutter_texture_get_pixbuf (ClutterTexture* texture); GdkPixbuf *clutter_texture_get_pixbuf (ClutterTexture* texture);