* clutter/clutter-texture.[ch]: (bug #675) added

clutter_texture_set_area_from_rgb_data, sharing some of the
initialization infrastructure with clutter_texture_set_from_rgb_data.
This commit is contained in:
Øyvind Kolås 2007-12-20 14:26:07 +00:00
parent 41c9528b4d
commit 06fe42dde9
3 changed files with 354 additions and 43 deletions

View File

@ -1,3 +1,9 @@
2007-12-19 Øyvind Kolås <pippin@o-hand.com>
* clutter/clutter-texture.[ch]: (bug #675) added
clutter_texture_set_area_from_rgb_data, sharing some of the
initialization infrastructure with clutter_texture_set_from_rgb_data.
2007-12-20 Emmanuele Bassi <ebassi@openedhand.com> 2007-12-20 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-container.c: * clutter/clutter-container.c:

View File

@ -426,14 +426,14 @@ texture_free_gl_resources (ClutterTexture *texture)
} }
} }
static void static void inline
texture_upload_data (ClutterTexture *texture, texture_upload_data (ClutterTexture *texture,
const guchar *data, const guchar *data,
gboolean has_alpha, gboolean has_alpha,
gint width, gint width,
gint height, gint height,
gint rowstride, gint rowstride,
gint bpp) gint bpp)
{ {
ClutterTexturePrivate *priv; ClutterTexturePrivate *priv;
gint x, y; gint x, y;
@ -1247,6 +1247,79 @@ clutter_texture_get_pixbuf (ClutterTexture* texture)
#endif #endif
} }
/* internal helper function for initialization of
* clutter_texture_set_from_rgb_data and clutter_texture_set_area_from_rgb_data.
*/
static inline gboolean
texture_prepare_upload (gboolean initialize,
ClutterTexture *texture,
const guchar *data,
gboolean has_alpha,
gint width,
gint height,
gint rowstride,
gint bpp,
ClutterTextureFlags flags,
guchar **copy_data,
gboolean *texture_dirty,
gboolean *size_change)
{
ClutterTexturePrivate *priv;
COGLenum prev_format;
priv = texture->priv;
g_return_val_if_fail (data != NULL, FALSE);
/* Needed for GL_RGBA (internal format) and gdk pixbuf usage */
g_return_val_if_fail (bpp == 4, FALSE);
if (initialize)
{
*texture_dirty = *size_change =
(width != priv->width || height != priv->height) ;
}
prev_format = priv->pixel_format;
if (has_alpha)
priv->pixel_format = CGL_RGBA;
else
priv->pixel_format = CGL_RGB;
if (flags & CLUTTER_TEXTURE_RGB_FLAG_BGR)
{
#if HAVE_COGL_GL
if (has_alpha)
priv->pixel_format = CGL_BGRA;
else
priv->pixel_format = CGL_BGR;
#else
/* GLES has no BGR format*/
*copy_data = rgb_to_bgr (data, has_alpha, width, height, rowstride);
#endif /* HAVE_COGL_GL */
}
if (flags & CLUTTER_TEXTURE_RGB_FLAG_PREMULT)
*copy_data = un_pre_multiply_alpha (data, width, height, rowstride);
if (initialize)
{
if (prev_format != priv->pixel_format || priv->pixel_type != PIXEL_TYPE)
*texture_dirty = TRUE;
}
else
{
if (prev_format != priv->pixel_format || priv->pixel_type != PIXEL_TYPE)
{
g_warning ("%s: pixel format or type mismatch", G_STRFUNC);
return FALSE;
}
}
priv->pixel_type = PIXEL_TYPE;
return TRUE;
}
/** /**
* clutter_texture_set_from_rgb_data: * clutter_texture_set_from_rgb_data:
* @texture: A #ClutterTexture * @texture: A #ClutterTexture
@ -1277,47 +1350,16 @@ clutter_texture_set_from_rgb_data (ClutterTexture *texture,
GError **error) GError **error)
{ {
ClutterTexturePrivate *priv; ClutterTexturePrivate *priv;
gboolean texture_dirty = TRUE, size_change = FALSE;
COGLenum prev_format;
guchar *copy_data = NULL; guchar *copy_data = NULL;
gboolean texture_dirty = TRUE, size_change = FALSE;
priv = texture->priv; priv = texture->priv;
if (!texture_prepare_upload (TRUE, texture, data, has_alpha, width, height, rowstride,
g_return_val_if_fail (data != NULL, FALSE); bpp, flags, &copy_data, &texture_dirty, &size_change))
/* Needed for GL_RGBA (internal format) and gdk pixbuf usage */
g_return_val_if_fail (bpp == 4, FALSE);
texture_dirty = size_change =
(width != priv->width || height != priv->height) ;
prev_format = priv->pixel_format;
if (has_alpha)
priv->pixel_format = CGL_RGBA;
else
priv->pixel_format = CGL_RGB;
if (flags & CLUTTER_TEXTURE_RGB_FLAG_BGR)
{ {
#if HAVE_COGL_GL return FALSE;
if (has_alpha)
priv->pixel_format = CGL_BGRA;
else
priv->pixel_format = CGL_BGR;
#else
/* GLES has no BGR format*/
copy_data = rgb_to_bgr (data, has_alpha, width, height, rowstride);
#endif /* HAVE_COGL_GL */
} }
if (flags & CLUTTER_TEXTURE_RGB_FLAG_PREMULT)
copy_data = un_pre_multiply_alpha (data, width, height, rowstride);
if (prev_format != priv->pixel_format || priv->pixel_type != PIXEL_TYPE)
texture_dirty = TRUE;
priv->pixel_type = PIXEL_TYPE;
priv->width = width; priv->width = width;
priv->height = height; priv->height = height;
@ -1781,3 +1823,253 @@ clutter_texture_is_tiled (ClutterTexture *texture)
return texture->priv->is_tiled; return texture->priv->is_tiled;
} }
static void inline
texture_update_data (ClutterTexture *texture,
const guchar *data,
gboolean has_alpha,
gint x0,
gint y0,
gint width,
gint height,
gint rowstride,
gint bpp)
{
ClutterTexturePrivate *priv;
gint x, y;
gint i = 0;
gboolean create_textures = FALSE;
priv = texture->priv;
g_return_if_fail (data != NULL);
CLUTTER_MARK();
if (!priv->is_tiled)
{
g_assert (priv->tiles);
CLUTTER_NOTE (TEXTURE, "syncing for single tile");
cogl_texture_bind (priv->target_type, priv->tiles[0]);
cogl_texture_set_alignment (priv->target_type, 4, width);
cogl_texture_set_filters
(priv->target_type,
priv->filter_quality ? CGL_LINEAR : CGL_NEAREST,
priv->filter_quality ? CGL_LINEAR : CGL_NEAREST);
cogl_texture_set_wrap (priv->target_type,
priv->repeat_x ? CGL_REPEAT : CGL_CLAMP_TO_EDGE,
priv->repeat_y ? CGL_REPEAT : CGL_CLAMP_TO_EDGE);
priv->filter_quality = 1;
cogl_texture_sub_image_2d (priv->target_type,
x0,
y0,
width,
height,
priv->pixel_format,
priv->pixel_type,
data);
return;
}
/* Multiple tiled texture */
CLUTTER_NOTE (TEXTURE,
"syncing for multiple tiles for %ix%i pixbuf",
priv->width, priv->height);
g_return_if_fail (priv->x_tiles != NULL && priv->y_tiles != NULL);
if (priv->tiles == NULL)
{
g_assert (0);
priv->tiles = g_new (COGLuint, priv->n_x_tiles * priv->n_y_tiles);
glGenTextures (priv->n_x_tiles * priv->n_y_tiles, priv->tiles);
create_textures = TRUE;
}
for (x = 0; x < priv->n_x_tiles; x++)
for (y = 0; y < priv->n_y_tiles; y++)
{
gint master_offset_x;
gint effective_x;
gint effective_width;
gint master_offset_y;
gint effective_y;
gint effective_height;
/*
-- first tile --
|--------------------- priv->width ------------------------------|
| <- priv->x_tiles[x].pos
|-----------| <- priv->x_tiles[x].size
|-------| <- x0
|------------| <- width
|--------------------| <- x0 + width
|-------| <- master_offset = -8
|-------| <- effective_x = 8
|---| <- effective_width
-- second tile ---
|--------------------- priv->width ------------------------------|
|-----------| <- priv->x_tiles[x].pos
|-----------| <- priv->x_tiles[x].size (src_w)
|-------| <- x0
|------------| <- width
|--------------------| <- x0 + width
|---| <- master_offset = 4
| <- effective_x (0 in between)
|--------| <- effective_width
XXXXXXXXXXXXXX <- master
|___________|___________|___________|___________|___________|_____%%%%%%|
*/
gint src_w, src_h;
src_w = priv->x_tiles[x].size;
src_h = priv->y_tiles[y].size;
/* skip tiles that do not intersect the updated region */
if ((priv->x_tiles[x].pos + src_w < x0 ||
priv->y_tiles[y].pos + src_h < y0 ||
priv->x_tiles[x].pos >= x0 + width ||
priv->y_tiles[y].pos >= y0 + height))
{
i++;
continue;
}
master_offset_x = priv->x_tiles[x].pos - x0;
if (priv->x_tiles[x].pos > x0)
effective_x = 0;
else
effective_x = x0 - priv->x_tiles[x].pos;
effective_width = (x0 + width) - priv->x_tiles[x].pos;
if (effective_width > src_w - effective_x)
effective_width = src_w - effective_x;
master_offset_y = priv->y_tiles[y].pos - y0;
if (priv->y_tiles[y].pos > y0)
effective_y = 0;
else
effective_y = y0 - priv->y_tiles[y].pos;
effective_height = (y0 + height) - priv->y_tiles[y].pos;
if (effective_height > src_h - effective_y)
effective_height = src_h - effective_y;
if (master_offset_x < 0)
master_offset_x = 0;
if (master_offset_y < 0)
master_offset_y = 0;
if (master_offset_x + effective_width > width)
effective_width = width - master_offset_x;
if (master_offset_y + effective_height > height)
effective_height = height - master_offset_y;
cogl_texture_bind (priv->target_type, priv->tiles[i]);
cogl_texture_set_alignment (priv->target_type, 4, rowstride/4);
cogl_texture_set_filters
(priv->target_type,
priv->filter_quality ? CGL_LINEAR : CGL_NEAREST,
priv->filter_quality ? CGL_LINEAR : CGL_NEAREST);
cogl_texture_set_wrap (priv->target_type,
priv->repeat_x ? CGL_REPEAT : CGL_CLAMP_TO_EDGE,
priv->repeat_y ? CGL_REPEAT : CGL_CLAMP_TO_EDGE);
cogl_texture_sub_image_2d (priv->target_type,
effective_x,
effective_y,
effective_width,
effective_height,
priv->pixel_format,
priv->pixel_type,
data + (master_offset_y * width + master_offset_x) * 4);
i++;
}
}
/**
* clutter_texture_set_area_from_rgb_data:
* @texture: A #ClutterTexture
* @data: Image data in RGB type colorspace.
* @has_alpha: Set to TRUE if image data has a alpha channel.
* @x: X coordinate of upper left corner of region to update.
* @y: Y coordinate of upper left corner of region to update.
* @width: Width in pixels of region to update.
* @height: Height in pixels of region to update.
* @rowstride: Distance in bytes between row starts.
* @bpp: bytes per pixel ( Currently only 4 supported )
* @flags: #ClutterTextureFlags
* @error: FIXME.
*
* Updates a subregion of the pixel data in a #ClutterTexture.
*
* Return value: TRUE on success, FALSE on failure.
*
* Since 0.6.
**/
gboolean
clutter_texture_set_area_from_rgb_data (ClutterTexture *texture,
const guchar *data,
gboolean has_alpha,
gint x,
gint y,
gint width,
gint height,
gint rowstride,
gint bpp,
ClutterTextureFlags flags,
GError **error)
{
ClutterTexturePrivate *priv;
guchar *copy_data = NULL;
priv = texture->priv;
if (!texture_prepare_upload (FALSE, texture, data, has_alpha, width, height, rowstride,
bpp, flags, &copy_data, NULL, NULL))
{
return FALSE;
}
texture_update_data (texture,
copy_data != NULL ? copy_data : data,
has_alpha,
x, y,
width, height,
rowstride,
bpp);
CLUTTER_ACTOR_SET_FLAGS (CLUTTER_ACTOR (texture), CLUTTER_ACTOR_REALIZED);
/* rename signal */
g_signal_emit (texture, texture_signals[PIXBUF_CHANGE], 0);
if (CLUTTER_ACTOR_IS_MAPPED (CLUTTER_ACTOR(texture)))
clutter_actor_queue_redraw (CLUTTER_ACTOR(texture));
if (copy_data != NULL)
g_free (copy_data);
return TRUE;
}

View File

@ -94,7 +94,7 @@ struct _ClutterTextureClass
* @CLUTTER_TEXTURE_YUV_FLAG_YUV2: FIXME * @CLUTTER_TEXTURE_YUV_FLAG_YUV2: FIXME
* *
* Flags for clutter_texture_set_from_rgb_data() and * Flags for clutter_texture_set_from_rgb_data() and
* clutter_texture_set_from_rgb_data(). * clutter_texture_set_from_yuv_data().
* *
* Since: 0.4 * Since: 0.4
*/ */
@ -119,6 +119,19 @@ gboolean clutter_texture_set_from_rgb_data (ClutterTexture *texture,
gint bpp, gint bpp,
ClutterTextureFlags flags, ClutterTextureFlags flags,
GError **error); GError **error);
gboolean clutter_texture_set_area_from_rgb_data (ClutterTexture *texture,
const guchar *data,
gboolean has_alpha,
gint x,
gint y,
gint width,
gint height,
gint rowstride,
gint bpp,
ClutterTextureFlags flags,
GError **error);
gboolean clutter_texture_set_from_yuv_data (ClutterTexture *texture, gboolean clutter_texture_set_from_yuv_data (ClutterTexture *texture,
const guchar *data, const guchar *data,
gint width, gint width,