mutter/clutter/clutter-texture.c

2554 lines
75 KiB
C
Raw Normal View History

2006-05-29 08:59:36 +00:00
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:clutter-texture
* @short_description: An actor for displaying and manipulating images.
*
* #ClutterTexture is a base class for displaying and manipulating pixel
* buffer type data.
*
* The clutter_texture_set_from_rgb_data() and
* clutter_texture_set_from_file() functions are used to copy image
* data into texture memory and subsequently realize the texture.
*
* If texture reads are supported by underlying GL implementation,
* unrealizing 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.
*
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com> Bug #815 - Split up request, allocation, and paint box * clutter/clutter-actor.[ch]: Rework the size allocation, request and paint area. Now ::request_coords() is called ::allocate(), and ::query_coords() has been split into ::get_preferred_width() and ::get_preferred_height(). See the documentation and the layout test on how to implement a container and layout manager with the new API. (#915, based on a patch by Havoc Pennington, Lucas Rocha and Johan Bilien) * clutter/clutter-clone-texture.c: Port CloneTexture to the new size negotiation API; it just means forwarding the requests to the parent texture. * clutter/clutter-deprecated.h: Add deprecated and replaced API. * clutter/clutter-entry.c: Port Entry to the new size negotiation API. * clutter/clutter-group.c: Port Group to the new size negotiation API; the semantics of the Group actor do not change. * clutter/clutter-label.c: Port Label to the new size negotiation API, and vastly simplify the code. * clutter/clutter-main.[ch]: Add API for executing a relayout when needed. * clutter/clutter-private.h: Add new Stage private API. * clutter/clutter-rectangle.c: Update the get_abs_opacity() call to get_paint_opacity(). * clutter/clutter-stage.c: (clutter_stage_get_preferred_width), (clutter_stage_get_preferred_height), (clutter_stage_allocate), (clutter_stage_class_init): Port Stage to the new size negotiation API. * clutter/clutter-texture.c: Port Texture to the new size negotiation API. * clutter/clutter-types.h: Add ClutterRequestMode enumeration. * clutter/x11/clutter-stage-x11.c: Port the X11 stage implementation to the new size negotiation API. * tests/Makefile.am: Add the layout manager test case. * tests/test-opacity.c: Update. * tests/test-project.c: Update. * tests/test-layout.c: Test case for a layout manager implemented using the new size negotiation API; the layout manager handles both transformed and untransformed children.
2008-06-10 17:07:52 +00:00
* Note: a ClutterTexture will scale its contents to fit the bounding
* box requested using clutter_actor_set_size(). To display an area of
* a texture without scaling, you should set the clip area using
* clutter_actor_set_clip().
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
2006-05-29 08:59:36 +00:00
#include "clutter-texture.h"
#include "clutter-main.h"
#include "clutter-marshal.h"
#include "clutter-feature.h"
#include "clutter-util.h"
2006-11-21 Emmanuele Bassi <ebassi@openedhand.com> * configure.ac: Enable debug messages also when --enable-debug is set to "minimum". * clutter/Makefile.am: * clutter/clutter-debug.h: Move all debugging macros inside this private header; make all debug macros depend on the CLUTTER_ENABLE_DEBUG compile time define, controlled by the --enable-debug configure switch; add G_LOG_DOMAIN define. * clutter/clutter-main.c: Clean up the debug stuff; add command line argument parsing using GOption; the debug messages now are triggered like this: CLUTTER_DEBUG=section:section:... clutter-app or like this: clutter-app --clutter-debug=section:section:... where "section" is one of the sections listed in clutter-main.c, or "all", for all sections; each section is bound to a flag, which can be used to define a domain when adding a debug note using the CLUTTER_NOTE() macro; the old CLUTTER_DBG() macro is just a wrapper around that, under the CLUTTER_DEBUG_MISC domain; CLUTTER_NOTE() is used like this: CLUTTER_NOTE (DOMAIN, log-function); where log function is g_printerr(), g_message(), g_warning(), g_critical() or directly g_log() - for instance: CLUTTER_NOTE (PANGO, g_warning ("Cache miss: %d", glyph)); will print the warning only if the "pango" flag has been set to the CLUTTER_DEBUG envvar or passed to the --clutter-debug command line argument. similar to CLUTTER_SHOW_FPS, there's also the --clutter-show-fps command line switch; also, the --display and --screen command line switches have been added: the first overrides the DISPLAY envvar and the second controls the X screen used by Clutter to get the root window on the display. * clutter/clutter-main.h: * clutter/clutter-main.c: Add extended support for GOption in Clutter; use clutter_init_with_args() to let Clutter parse your own command line arguments; use instead clutter_get_option_group() to get the GOptionGroup used by Clutter if you want to do the parsing yourself with g_option_context_parse(). The init sequence has been verified, updated and moved into common functions where possible. * clutter/pango/pangoclutter-render.c: * clutter/*.c: Include "clutter-debug.h" where needed; use CLUTTER_NOTE() instead of CLUTTER_DBG(). * examples/super-oh.c: Use the new clutter_init_with_args() function, and add a --num-hands command line switch to the SuperOH example code controlling the number of hands at runtime.
2006-11-21 21:27:53 +00:00
#include "clutter-private.h"
#include "clutter-scriptable.h"
2006-11-21 Emmanuele Bassi <ebassi@openedhand.com> * configure.ac: Enable debug messages also when --enable-debug is set to "minimum". * clutter/Makefile.am: * clutter/clutter-debug.h: Move all debugging macros inside this private header; make all debug macros depend on the CLUTTER_ENABLE_DEBUG compile time define, controlled by the --enable-debug configure switch; add G_LOG_DOMAIN define. * clutter/clutter-main.c: Clean up the debug stuff; add command line argument parsing using GOption; the debug messages now are triggered like this: CLUTTER_DEBUG=section:section:... clutter-app or like this: clutter-app --clutter-debug=section:section:... where "section" is one of the sections listed in clutter-main.c, or "all", for all sections; each section is bound to a flag, which can be used to define a domain when adding a debug note using the CLUTTER_NOTE() macro; the old CLUTTER_DBG() macro is just a wrapper around that, under the CLUTTER_DEBUG_MISC domain; CLUTTER_NOTE() is used like this: CLUTTER_NOTE (DOMAIN, log-function); where log function is g_printerr(), g_message(), g_warning(), g_critical() or directly g_log() - for instance: CLUTTER_NOTE (PANGO, g_warning ("Cache miss: %d", glyph)); will print the warning only if the "pango" flag has been set to the CLUTTER_DEBUG envvar or passed to the --clutter-debug command line argument. similar to CLUTTER_SHOW_FPS, there's also the --clutter-show-fps command line switch; also, the --display and --screen command line switches have been added: the first overrides the DISPLAY envvar and the second controls the X screen used by Clutter to get the root window on the display. * clutter/clutter-main.h: * clutter/clutter-main.c: Add extended support for GOption in Clutter; use clutter_init_with_args() to let Clutter parse your own command line arguments; use instead clutter_get_option_group() to get the GOptionGroup used by Clutter if you want to do the parsing yourself with g_option_context_parse(). The init sequence has been verified, updated and moved into common functions where possible. * clutter/pango/pangoclutter-render.c: * clutter/*.c: Include "clutter-debug.h" where needed; use CLUTTER_NOTE() instead of CLUTTER_DBG(). * examples/super-oh.c: Use the new clutter_init_with_args() function, and add a --num-hands command line switch to the SuperOH example code controlling the number of hands at runtime.
2006-11-21 21:27:53 +00:00
#include "clutter-debug.h"
#include "clutter-fixed.h"
#include "clutter-enum-types.h"
2006-05-29 08:59:36 +00:00
#include "cogl/cogl.h"
2006-05-29 08:59:36 +00:00
static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
2006-05-29 08:59:36 +00:00
G_DEFINE_TYPE_WITH_CODE (ClutterTexture,
clutter_texture,
CLUTTER_TYPE_ACTOR,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
clutter_scriptable_iface_init));
2006-05-29 08:59:36 +00:00
#define CLUTTER_TEXTURE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_TEXTURE, ClutterTexturePrivate))
typedef struct _ClutterTextureAsyncData ClutterTextureAsyncData;
struct _ClutterTexturePrivate
2006-05-29 08:59:36 +00:00
{
gint width;
gint height;
gint max_tile_waste;
ClutterTextureQuality filter_quality;
CoglHandle material;
CoglHandle fbo_texture;
gboolean no_slice;
ClutterActor *fbo_source;
CoglHandle fbo_handle;
/* Non video memory copy of image data */
guint local_data_width, local_data_height;
guint local_data_rowstride;
guint local_data_has_alpha;
guchar *local_data;
guint sync_actor_size : 1;
guint repeat_x : 1;
guint repeat_y : 1;
guint in_dispose : 1;
guint keep_aspect_ratio : 1;
2009-03-11 18:26:30 +00:00
guint load_size_async : 1;
guint load_data_async : 1;
guint load_async_set : 1; /* used to make load_async
possible */
ClutterTextureAsyncData *async_data;
};
struct _ClutterTextureAsyncData
{
/* Mutex used to synchronize setting the abort flag */
GMutex *mutex;
/* If set to true, the loaded data will be discarded */
gboolean abort;
/* The texture for which the data is being loaded */
ClutterTexture *texture;
/* Source ID of the idle handler for loading. If this is zero then
the data is being loaded in a thread from the thread pool. Once
the thread is finished it will be converted to idle load handler
and load_idle will be nonzero. If load_idle is nonzero then the
rest of the load can safely be aborted by just removing the
source, otherwise the abort flag needs to be set and the data
should be disowned */
guint load_idle;
gchar *load_filename;
CoglBitmap *load_bitmap;
GError *load_error;
2006-05-29 08:59:36 +00:00
};
enum
{
PROP_0,
PROP_NO_SLICE,
2006-05-29 08:59:36 +00:00
PROP_MAX_TILE_WASTE,
PROP_PIXEL_FORMAT, /* Texture format */
PROP_SYNC_SIZE,
PROP_REPEAT_Y,
PROP_REPEAT_X,
PROP_FILTER_QUALITY,
PROP_COGL_TEXTURE,
PROP_COGL_MATERIAL,
PROP_FILENAME,
PROP_KEEP_ASPECT_RATIO,
2009-03-11 18:26:30 +00:00
PROP_LOAD_ASYNC,
PROP_LOAD_DATA_ASYNC,
2006-05-29 08:59:36 +00:00
};
enum
{
SIZE_CHANGE,
PIXBUF_CHANGE,
LOAD_SUCCESS,
LOAD_FINISHED,
2006-05-29 08:59:36 +00:00
LAST_SIGNAL
};
static int texture_signals[LAST_SIGNAL] = { 0 };
static GThreadPool *async_thread_pool = NULL;
static void
texture_fbo_free_resources (ClutterTexture *texture);
2006-05-29 08:59:36 +00:00
static void
clutter_texture_save_to_local_data (ClutterTexture *texture);
2006-05-29 08:59:36 +00:00
static void
clutter_texture_load_from_local_data (ClutterTexture *texture);
GQuark
clutter_texture_error_quark (void)
{
return g_quark_from_static_string ("clutter-texture-error-quark");
2006-05-29 08:59:36 +00:00
}
static inline void
clutter_texture_quality_to_filters (ClutterTextureQuality quality,
gint *min_filter_p,
gint *mag_filter_p)
{
gint min_filter, mag_filter;
switch (quality)
{
case CLUTTER_TEXTURE_QUALITY_LOW:
min_filter = CGL_NEAREST;
mag_filter = CGL_NEAREST;
break;
case CLUTTER_TEXTURE_QUALITY_MEDIUM:
min_filter = CGL_LINEAR;
mag_filter = CGL_LINEAR;
break;
case CLUTTER_TEXTURE_QUALITY_HIGH:
min_filter = CGL_LINEAR_MIPMAP_LINEAR;
mag_filter = CGL_LINEAR;
break;
}
if (min_filter_p)
*min_filter_p = min_filter;
if (mag_filter_p)
*mag_filter_p = mag_filter;
}
2006-05-29 08:59:36 +00:00
static void
texture_free_gl_resources (ClutterTexture *texture)
2006-05-29 08:59:36 +00:00
{
ClutterTexturePrivate *priv = texture->priv;
2006-05-29 08:59:36 +00:00
CLUTTER_MARK();
if (priv->material != COGL_INVALID_HANDLE)
cogl_material_remove_layer (priv->material, 0);
2006-05-29 08:59:36 +00:00
}
static void
clutter_texture_unrealize (ClutterActor *actor)
{
ClutterTexture *texture;
ClutterTexturePrivate *priv;
texture = CLUTTER_TEXTURE(actor);
priv = texture->priv;
if (priv->material == COGL_INVALID_HANDLE)
return;
/* there's no need to read the pixels back when unrealizing inside
* a dispose run, and the dispose() call will release the GL
* texture data as well, so we can safely bail out now
*/
if ((CLUTTER_PRIVATE_FLAGS (actor) & CLUTTER_ACTOR_IN_DESTRUCTION) ||
priv->in_dispose)
return;
CLUTTER_MARK();
if (priv->fbo_source != COGL_INVALID_HANDLE)
{
/* Free up our fbo handle and texture resources, realize will recreate */
cogl_offscreen_unref (priv->fbo_handle);
priv->fbo_handle = COGL_INVALID_HANDLE;
texture_free_gl_resources (texture);
return;
}
if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_READ_PIXELS))
{
/* Move image data from video to main memory.
* GL/ES cant do this - it probably makes sense
* to move this kind of thing into a ClutterProxyTexture
* where this behaviour can be better controlled.
*
* Or make it controllable via a property.
*/
if (priv->local_data == NULL)
{
clutter_texture_save_to_local_data (texture);
CLUTTER_NOTE (TEXTURE, "moved pixels into system mem");
}
texture_free_gl_resources (texture);
}
CLUTTER_NOTE (TEXTURE, "Texture unrealized");
}
2006-05-29 08:59:36 +00:00
static void
clutter_texture_realize (ClutterActor *actor)
2006-05-29 08:59:36 +00:00
{
ClutterTexture *texture;
ClutterTexturePrivate *priv;
2006-05-29 08:59:36 +00:00
texture = CLUTTER_TEXTURE(actor);
priv = texture->priv;
2006-05-29 08:59:36 +00:00
CLUTTER_MARK();
if (priv->fbo_source)
{
CoglTextureFlags flags = COGL_TEXTURE_NONE;
gint min_filter, mag_filter;
gint max_waste = -1;
/* Handle FBO's */
if (priv->fbo_texture != COGL_INVALID_HANDLE)
cogl_texture_unref (priv->fbo_texture);
if (!priv->no_slice)
max_waste = priv->max_tile_waste;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
priv->fbo_texture =
cogl_texture_new_with_size (priv->width,
priv->height,
max_waste, flags,
COGL_PIXEL_FORMAT_RGBA_8888);
clutter_texture_quality_to_filters (priv->filter_quality,
&min_filter,
&mag_filter);
cogl_texture_set_filters (priv->fbo_texture, min_filter, mag_filter);
priv->fbo_handle = cogl_offscreen_new_to_texture (priv->fbo_texture);
if (priv->fbo_handle == COGL_INVALID_HANDLE)
{
g_warning ("%s: Offscreen texture creation failed", G_STRLOC);
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
}
clutter_actor_set_size (actor, priv->width, priv->height);
return;
}
if (priv->local_data != NULL)
{
/* Move any local image data we have from unrealization
* back into video memory.
*/
clutter_texture_load_from_local_data (texture);
}
else
2006-05-29 08:59:36 +00:00
{
if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_READ_PIXELS))
{
/* Dont allow realization with no data - note set_data
* will set realize flags.
*/
CLUTTER_NOTE (TEXTURE,
"Texture has no image data cannot realize");
CLUTTER_NOTE (TEXTURE, "flags %i", actor->flags);
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
CLUTTER_NOTE (TEXTURE, "flags %i", actor->flags);
return;
}
2006-05-29 08:59:36 +00:00
}
CLUTTER_NOTE (TEXTURE, "Texture realized");
2006-05-29 08:59:36 +00:00
}
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com> Bug #815 - Split up request, allocation, and paint box * clutter/clutter-actor.[ch]: Rework the size allocation, request and paint area. Now ::request_coords() is called ::allocate(), and ::query_coords() has been split into ::get_preferred_width() and ::get_preferred_height(). See the documentation and the layout test on how to implement a container and layout manager with the new API. (#915, based on a patch by Havoc Pennington, Lucas Rocha and Johan Bilien) * clutter/clutter-clone-texture.c: Port CloneTexture to the new size negotiation API; it just means forwarding the requests to the parent texture. * clutter/clutter-deprecated.h: Add deprecated and replaced API. * clutter/clutter-entry.c: Port Entry to the new size negotiation API. * clutter/clutter-group.c: Port Group to the new size negotiation API; the semantics of the Group actor do not change. * clutter/clutter-label.c: Port Label to the new size negotiation API, and vastly simplify the code. * clutter/clutter-main.[ch]: Add API for executing a relayout when needed. * clutter/clutter-private.h: Add new Stage private API. * clutter/clutter-rectangle.c: Update the get_abs_opacity() call to get_paint_opacity(). * clutter/clutter-stage.c: (clutter_stage_get_preferred_width), (clutter_stage_get_preferred_height), (clutter_stage_allocate), (clutter_stage_class_init): Port Stage to the new size negotiation API. * clutter/clutter-texture.c: Port Texture to the new size negotiation API. * clutter/clutter-types.h: Add ClutterRequestMode enumeration. * clutter/x11/clutter-stage-x11.c: Port the X11 stage implementation to the new size negotiation API. * tests/Makefile.am: Add the layout manager test case. * tests/test-opacity.c: Update. * tests/test-project.c: Update. * tests/test-layout.c: Test case for a layout manager implemented using the new size negotiation API; the layout manager handles both transformed and untransformed children.
2008-06-10 17:07:52 +00:00
static void
clutter_texture_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
{
ClutterTexture *texture = CLUTTER_TEXTURE (self);
ClutterTexturePrivate *priv = texture->priv;
/* Min request is always 0 since we can scale down or clip */
if (min_width_p)
*min_width_p = 0;
if (priv->sync_actor_size)
{
if (natural_width_p)
{
if (!priv->keep_aspect_ratio ||
for_height < 0 ||
priv->height <= 0)
{
*natural_width_p = CLUTTER_UNITS_FROM_DEVICE (priv->width);
}
else
{
/* Set the natural width so as to preserve the aspect ratio */
gfloat ratio, height;
ratio = (float)(priv->width) / (float)(priv->height);
height = CLUTTER_UNITS_TO_FLOAT (for_height);
*natural_width_p =
CLUTTER_UNITS_FROM_FLOAT (ratio * height);
}
}
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com> Bug #815 - Split up request, allocation, and paint box * clutter/clutter-actor.[ch]: Rework the size allocation, request and paint area. Now ::request_coords() is called ::allocate(), and ::query_coords() has been split into ::get_preferred_width() and ::get_preferred_height(). See the documentation and the layout test on how to implement a container and layout manager with the new API. (#915, based on a patch by Havoc Pennington, Lucas Rocha and Johan Bilien) * clutter/clutter-clone-texture.c: Port CloneTexture to the new size negotiation API; it just means forwarding the requests to the parent texture. * clutter/clutter-deprecated.h: Add deprecated and replaced API. * clutter/clutter-entry.c: Port Entry to the new size negotiation API. * clutter/clutter-group.c: Port Group to the new size negotiation API; the semantics of the Group actor do not change. * clutter/clutter-label.c: Port Label to the new size negotiation API, and vastly simplify the code. * clutter/clutter-main.[ch]: Add API for executing a relayout when needed. * clutter/clutter-private.h: Add new Stage private API. * clutter/clutter-rectangle.c: Update the get_abs_opacity() call to get_paint_opacity(). * clutter/clutter-stage.c: (clutter_stage_get_preferred_width), (clutter_stage_get_preferred_height), (clutter_stage_allocate), (clutter_stage_class_init): Port Stage to the new size negotiation API. * clutter/clutter-texture.c: Port Texture to the new size negotiation API. * clutter/clutter-types.h: Add ClutterRequestMode enumeration. * clutter/x11/clutter-stage-x11.c: Port the X11 stage implementation to the new size negotiation API. * tests/Makefile.am: Add the layout manager test case. * tests/test-opacity.c: Update. * tests/test-project.c: Update. * tests/test-layout.c: Test case for a layout manager implemented using the new size negotiation API; the layout manager handles both transformed and untransformed children.
2008-06-10 17:07:52 +00:00
}
else
{
if (natural_width_p)
*natural_width_p = 0;
}
}
static void
clutter_texture_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
{
ClutterTexture *texture = CLUTTER_TEXTURE (self);
ClutterTexturePrivate *priv = texture->priv;
/* Min request is always 0 since we can scale down or clip */
if (min_height_p)
*min_height_p = 0;
if (priv->sync_actor_size)
{
if (natural_height_p)
{
if (!priv->keep_aspect_ratio ||
for_width < 0 ||
priv->width <= 0)
{
*natural_height_p = CLUTTER_UNITS_FROM_DEVICE (priv->height);
}
else
{
/* Set the natural height so as to preserve the aspect ratio */
gfloat ratio, width;
ratio = (float)(priv->height) / (float)(priv->width);
width = CLUTTER_UNITS_TO_FLOAT (for_width);
*natural_height_p =
CLUTTER_UNITS_FROM_FLOAT (ratio * width);
}
}
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com> Bug #815 - Split up request, allocation, and paint box * clutter/clutter-actor.[ch]: Rework the size allocation, request and paint area. Now ::request_coords() is called ::allocate(), and ::query_coords() has been split into ::get_preferred_width() and ::get_preferred_height(). See the documentation and the layout test on how to implement a container and layout manager with the new API. (#915, based on a patch by Havoc Pennington, Lucas Rocha and Johan Bilien) * clutter/clutter-clone-texture.c: Port CloneTexture to the new size negotiation API; it just means forwarding the requests to the parent texture. * clutter/clutter-deprecated.h: Add deprecated and replaced API. * clutter/clutter-entry.c: Port Entry to the new size negotiation API. * clutter/clutter-group.c: Port Group to the new size negotiation API; the semantics of the Group actor do not change. * clutter/clutter-label.c: Port Label to the new size negotiation API, and vastly simplify the code. * clutter/clutter-main.[ch]: Add API for executing a relayout when needed. * clutter/clutter-private.h: Add new Stage private API. * clutter/clutter-rectangle.c: Update the get_abs_opacity() call to get_paint_opacity(). * clutter/clutter-stage.c: (clutter_stage_get_preferred_width), (clutter_stage_get_preferred_height), (clutter_stage_allocate), (clutter_stage_class_init): Port Stage to the new size negotiation API. * clutter/clutter-texture.c: Port Texture to the new size negotiation API. * clutter/clutter-types.h: Add ClutterRequestMode enumeration. * clutter/x11/clutter-stage-x11.c: Port the X11 stage implementation to the new size negotiation API. * tests/Makefile.am: Add the layout manager test case. * tests/test-opacity.c: Update. * tests/test-project.c: Update. * tests/test-layout.c: Test case for a layout manager implemented using the new size negotiation API; the layout manager handles both transformed and untransformed children.
2008-06-10 17:07:52 +00:00
}
else
{
if (natural_height_p)
*natural_height_p = 0;
}
}
static void
clutter_texture_allocate (ClutterActor *self,
const ClutterActorBox *box,
gboolean origin_changed)
{
ClutterTexturePrivate *priv = CLUTTER_TEXTURE (self)->priv;
/* chain up to set actor->allocation */
CLUTTER_ACTOR_CLASS (clutter_texture_parent_class)->allocate (self, box,
origin_changed);
/* If we adopted the source fbo then allocate that at its preferred
size */
if (priv->fbo_source && clutter_actor_get_parent (priv->fbo_source) == self)
clutter_actor_allocate_preferred_size (priv->fbo_source, origin_changed);
}
static void
clutter_texture_set_fbo_projection (ClutterActor *self)
{
ClutterTexturePrivate *priv = CLUTTER_TEXTURE (self)->priv;
ClutterVertex verts[4];
gfloat viewport[4];
ClutterUnit x_min, x_max, y_min, y_max;
gfloat tx_min, tx_max, ty_min, ty_max;
gfloat tan_angle, near_size;
ClutterPerspective perspective;
ClutterStage *stage;
int i;
/* Get the bounding rectangle of the source as drawn in screen
coordinates */
clutter_actor_get_abs_allocation_vertices (priv->fbo_source, verts);
x_min = x_max = verts[0].x;
y_min = y_max = verts[0].y;
for (i = 1; i < G_N_ELEMENTS (verts); ++i)
{
if (verts[i].x < x_min)
x_min = verts[i].x;
if (verts[i].x > x_max)
x_max = verts[i].x;
if (verts[i].y < y_min)
y_min = verts[i].y;
if (verts[i].y > y_max)
y_max = verts[i].y;
}
stage = CLUTTER_STAGE (clutter_actor_get_stage (self));
clutter_stage_get_perspective (stage, &perspective);
/* Convert the coordinates back to [-1,1] range */
cogl_get_viewport (viewport);
tx_min = (CLUTTER_UNITS_TO_FLOAT (x_min) / viewport[2])
* 2 - 1.0;
tx_max = (CLUTTER_UNITS_TO_FLOAT (x_max) / viewport[2])
* 2 - 1.0;
ty_min = (CLUTTER_UNITS_TO_FLOAT (y_min) / viewport[3])
* 2 - 1.0;
ty_max = (CLUTTER_UNITS_TO_FLOAT (y_max) / viewport[3])
* 2 - 1.0;
/* Set up a projection matrix so that the actor will be projected as
if it was drawn at its original location */
tan_angle = tanf ((perspective.fovy / 2) * (G_PI / 180.0));
near_size = perspective.z_near * tan_angle;
cogl_frustum ((tx_min * near_size),
(tx_max * near_size),
(-ty_min * near_size),
(-ty_max * near_size),
perspective.z_near,
perspective.z_far);
}
2006-05-29 08:59:36 +00:00
static void
clutter_texture_paint (ClutterActor *self)
2006-05-29 08:59:36 +00:00
{
ClutterTexture *texture = CLUTTER_TEXTURE (self);
ClutterTexturePrivate *priv = texture->priv;
gint x_1, y_1, x_2, y_2;
CoglColor transparent_col;
gfloat t_w, t_h;
guint8 paint_opacity = clutter_actor_get_paint_opacity (self);
if (paint_opacity == 0)
{
/* Bail early if painting the actor would be a no-op, custom actors that
* might cause a lot of work/state changes should all do this.
*/
return;
}
2006-05-29 08:59:36 +00:00
if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR(texture)))
clutter_actor_realize (CLUTTER_ACTOR(texture));
if (priv->fbo_handle != COGL_INVALID_HANDLE)
{
ClutterMainContext *context;
ClutterShader *shader = NULL;
ClutterActor *stage = NULL;
ClutterPerspective perspective;
context = clutter_context_get_default ();
if (context->shaders)
shader = clutter_actor_get_shader (context->shaders->data);
/* Temporarily turn of the shader on the top of the context's
* shader stack, to restore the GL pipeline to it's natural state.
*/
if (shader)
clutter_shader_set_is_enabled (shader, FALSE);
/* Redirect drawing to the fbo */
cogl_draw_buffer (COGL_OFFSCREEN_BUFFER, priv->fbo_handle);
if ((stage = clutter_actor_get_stage (self)))
{
guint stage_width, stage_height;
ClutterActor *source_parent;
clutter_stage_get_perspective (CLUTTER_STAGE (stage), &perspective);
clutter_actor_get_size (stage, &stage_width, &stage_height);
/* Use below to set the modelview matrix as if the viewport
was still the same size as the stage */
cogl_setup_viewport (stage_width, stage_height,
perspective.fovy,
perspective.aspect,
perspective.z_near,
perspective.z_far);
/* Use a projection matrix that makes the actor appear as it
would if it was rendered at its normal screen location */
clutter_texture_set_fbo_projection (self);
/* Reset the viewport to the size of the FBO */
cogl_viewport (priv->width, priv->height);
/* Reapply the source's parent transformations */
if ((source_parent = clutter_actor_get_parent (priv->fbo_source)))
_clutter_actor_apply_modelview_transform_recursive (source_parent,
NULL);
}
/* cogl_clear is called to clear the buffers */
cogl_color_set_from_4ub (&transparent_col, 0, 0, 0, 0);
cogl_clear (&transparent_col);
cogl_disable_fog ();
/* Clear the clipping stack so that if the FBO actor is being
clipped then it won't affect drawing the source */
cogl_clip_stack_save ();
/* Render out actor scene to fbo */
clutter_actor_paint (priv->fbo_source);
cogl_clip_stack_restore ();
/* Restore drawing to the frame buffer */
cogl_draw_buffer (COGL_WINDOW_BUFFER, COGL_INVALID_HANDLE);
/* Restore the perspective matrix using cogl_perspective so that
the inverse matrix will be right */
cogl_perspective (perspective.fovy,
perspective.aspect,
perspective.z_near,
perspective.z_far);
/* If there is a shader on top of the shader stack, turn it back on. */
if (shader)
clutter_shader_set_is_enabled (shader, TRUE);
}
/* A clone may need to fire above if were a TFP/FBO but not visible.
* Ultimatly needs some reworking with maybe an extra prepare_paint
* method or some such.
*/
if (CLUTTER_PRIVATE_FLAGS(self) & CLUTTER_TEXTURE_IN_CLONE_PAINT)
return;
2006-11-21 Emmanuele Bassi <ebassi@openedhand.com> * configure.ac: Enable debug messages also when --enable-debug is set to "minimum". * clutter/Makefile.am: * clutter/clutter-debug.h: Move all debugging macros inside this private header; make all debug macros depend on the CLUTTER_ENABLE_DEBUG compile time define, controlled by the --enable-debug configure switch; add G_LOG_DOMAIN define. * clutter/clutter-main.c: Clean up the debug stuff; add command line argument parsing using GOption; the debug messages now are triggered like this: CLUTTER_DEBUG=section:section:... clutter-app or like this: clutter-app --clutter-debug=section:section:... where "section" is one of the sections listed in clutter-main.c, or "all", for all sections; each section is bound to a flag, which can be used to define a domain when adding a debug note using the CLUTTER_NOTE() macro; the old CLUTTER_DBG() macro is just a wrapper around that, under the CLUTTER_DEBUG_MISC domain; CLUTTER_NOTE() is used like this: CLUTTER_NOTE (DOMAIN, log-function); where log function is g_printerr(), g_message(), g_warning(), g_critical() or directly g_log() - for instance: CLUTTER_NOTE (PANGO, g_warning ("Cache miss: %d", glyph)); will print the warning only if the "pango" flag has been set to the CLUTTER_DEBUG envvar or passed to the --clutter-debug command line argument. similar to CLUTTER_SHOW_FPS, there's also the --clutter-show-fps command line switch; also, the --display and --screen command line switches have been added: the first overrides the DISPLAY envvar and the second controls the X screen used by Clutter to get the root window on the display. * clutter/clutter-main.h: * clutter/clutter-main.c: Add extended support for GOption in Clutter; use clutter_init_with_args() to let Clutter parse your own command line arguments; use instead clutter_get_option_group() to get the GOptionGroup used by Clutter if you want to do the parsing yourself with g_option_context_parse(). The init sequence has been verified, updated and moved into common functions where possible. * clutter/pango/pangoclutter-render.c: * clutter/*.c: Include "clutter-debug.h" where needed; use CLUTTER_NOTE() instead of CLUTTER_DBG(). * examples/super-oh.c: Use the new clutter_init_with_args() function, and add a --num-hands command line switch to the SuperOH example code controlling the number of hands at runtime.
2006-11-21 21:27:53 +00:00
CLUTTER_NOTE (PAINT,
"painting texture '%s'",
clutter_actor_get_name (self) ? clutter_actor_get_name (self)
: "unknown");
cogl_material_set_color4ub (priv->material, 0xff, 0xff, 0xff, paint_opacity);
2006-05-29 08:59:36 +00:00
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com> Bug #815 - Split up request, allocation, and paint box * clutter/clutter-actor.[ch]: Rework the size allocation, request and paint area. Now ::request_coords() is called ::allocate(), and ::query_coords() has been split into ::get_preferred_width() and ::get_preferred_height(). See the documentation and the layout test on how to implement a container and layout manager with the new API. (#915, based on a patch by Havoc Pennington, Lucas Rocha and Johan Bilien) * clutter/clutter-clone-texture.c: Port CloneTexture to the new size negotiation API; it just means forwarding the requests to the parent texture. * clutter/clutter-deprecated.h: Add deprecated and replaced API. * clutter/clutter-entry.c: Port Entry to the new size negotiation API. * clutter/clutter-group.c: Port Group to the new size negotiation API; the semantics of the Group actor do not change. * clutter/clutter-label.c: Port Label to the new size negotiation API, and vastly simplify the code. * clutter/clutter-main.[ch]: Add API for executing a relayout when needed. * clutter/clutter-private.h: Add new Stage private API. * clutter/clutter-rectangle.c: Update the get_abs_opacity() call to get_paint_opacity(). * clutter/clutter-stage.c: (clutter_stage_get_preferred_width), (clutter_stage_get_preferred_height), (clutter_stage_allocate), (clutter_stage_class_init): Port Stage to the new size negotiation API. * clutter/clutter-texture.c: Port Texture to the new size negotiation API. * clutter/clutter-types.h: Add ClutterRequestMode enumeration. * clutter/x11/clutter-stage-x11.c: Port the X11 stage implementation to the new size negotiation API. * tests/Makefile.am: Add the layout manager test case. * tests/test-opacity.c: Update. * tests/test-project.c: Update. * tests/test-layout.c: Test case for a layout manager implemented using the new size negotiation API; the layout manager handles both transformed and untransformed children.
2008-06-10 17:07:52 +00:00
clutter_actor_get_allocation_coords (self, &x_1, &y_1, &x_2, &y_2);
CLUTTER_NOTE (PAINT, "paint to x1: %i, y1: %i x2: %i, y2: %i "
"opacity: %i",
x_1, y_1, x_2, y_2,
clutter_actor_get_opacity (self));
if (priv->repeat_x && priv->width > 0)
t_w = (float) (x_2 - x_1) / (float) (priv->width);
else
t_w = 1.0;
2008-10-30 Emmanuele Bassi <ebassi@linux.intel.com> Bug 1209 - Move fixed point API in COGL * clutter/cogl/cogl-fixed.h: * clutter/cogl/cogl.h.in: * clutter/cogl/common/Makefile.am: * clutter/cogl/common/cogl-fixed.c: Add fixed point API, modelled after the ClutterFixed. The CoglFixed API supercedes the ClutterFixed one and avoids the dependency of COGL on Clutter's own API. * clutter/cogl/common/cogl-clip-stack.c: * clutter/cogl/common/cogl-primitives.c: * clutter/cogl/common/cogl-primitives.h: Update internal usage of ClutterFixed to CoglFixed. * clutter/cogl/gl/Makefile.am: * clutter/cogl/gl/cogl-primitives.c: * clutter/cogl/gl/cogl-texture.c: * clutter/cogl/gl/cogl.c: Ditto, in the GL implementation of the COGL API. * clutter/cogl/gles/Makefile.am: * clutter/cogl/gles/cogl-fbo.c: * clutter/cogl/gles/cogl-gles2-wrapper.c: * clutter/cogl/gles/cogl-primitives.c: * clutter/cogl/gles/cogl-texture.c: * clutter/cogl/gles/cogl.c: Ditto, in the GLES implementation of the COGL API. * clutter/pango/pangoclutter-glyph-cache.c: * clutter/pango/pangoclutter-glyph-cache.h: Ditto, in the Pango renderer glyphs cache. * clutter/clutter-fixed.c: * clutter/clutter-fixed.h: ClutterFixed and related API becomes a simple transition API for bindings and public Clutter API. * clutter/clutter-actor.c: * clutter/clutter-alpha.c: * clutter/clutter-backend.c: * clutter/clutter-behaviour-depth.c: * clutter/clutter-behaviour-ellipse.c: * clutter/clutter-behaviour-path.c: * clutter/clutter-behaviour-rotate.c: * clutter/clutter-behaviour-scale.c: * clutter/clutter-clone-texture.c: * clutter/clutter-color.c: * clutter/clutter-entry.c: * clutter/clutter-stage.c: * clutter/clutter-texture.c: * clutter/clutter-timeline.c: * clutter/clutter-units.h: Move from the internal usage of ClutterFixed to CoglFixed. * doc/reference/clutter/clutter-sections.txt: * doc/reference/cogl/cogl-docs.sgml: * doc/reference/cogl/cogl-sections.txt: Update the documentation. * tests/test-cogl-tex-tile.c: * tests/test-project.c: Fix tests after the API change * README: Add release notes.
2008-10-30 16:37:55 +00:00
if (priv->repeat_y && priv->height > 0)
t_h = (float) (y_2 - y_1) / (float) (priv->height);
else
t_h = 1.0;
/* Paint will have translated us */
cogl_set_source (priv->material);
Fully integrates CoglMaterial throughout the rest of Cogl This glues CoglMaterial in as the fundamental way that Cogl describes how to fill in geometry. It adds cogl_set_source (), which is used to set the material which will be used by all subsequent drawing functions It adds cogl_set_source_texture as a convenience for setting up a default material with a single texture layer, and cogl_set_source_color is now also a convenience for setting up a material with a solid fill. "drawing functions" include, cogl_rectangle, cogl_texture_rectangle, cogl_texture_multiple_rectangles, cogl_texture_polygon (though the cogl_texture_* funcs have been renamed; see below for details), cogl_path_fill/stroke and cogl_vertex_buffer_draw*. cogl_texture_rectangle, cogl_texture_multiple_rectangles and cogl_texture_polygon no longer take a texture handle; instead the current source material is referenced. The functions have also been renamed to: cogl_rectangle_with_texture_coords, cogl_rectangles_with_texture_coords and cogl_polygon respectivly. Most code that previously did: cogl_texture_rectangle (tex_handle, x, y,...); needs to be changed to now do: cogl_set_source_texture (tex_handle); cogl_rectangle_with_texture_coords (x, y,....); In the less likely case where you were blending your source texture with a color like: cogl_set_source_color4ub (r,g,b,a); /* where r,g,b,a isn't just white */ cogl_texture_rectangle (tex_handle, x, y,...); you will need your own material to do that: mat = cogl_material_new (); cogl_material_set_color4ub (r,g,b,a); cogl_material_set_layer (mat, 0, tex_handle)); cogl_set_source_material (mat); Code that uses the texture coordinates, 0, 0, 1, 1 don't need to use cog_rectangle_with_texure_coords since these are the coordinates that cogl_rectangle will use. For cogl_texture_polygon; as well as dropping the texture handle, the n_vertices and vertices arguments were transposed for consistency. So code previously written as: cogl_texture_polygon (tex_handle, 3, verts, TRUE); need to be written as: cogl_set_source_texture (tex_handle); cogl_polygon (verts, 3, TRUE); All of the unit tests have been updated to now use the material API and test-cogl-material has been renamed to test-cogl-multitexture since any textured quad is now technically a test of CoglMaterial but this test specifically creates a material with multiple texture layers. Note: The GLES backend has not been updated yet; that will be done in a following commit.
2009-01-23 16:15:40 +00:00
cogl_rectangle_with_texture_coords (0, 0,
(float) (x_2 - x_1),
(float) (y_2 - y_1),
0, 0, t_w, t_h);
2006-05-29 08:59:36 +00:00
}
static void
clutter_texture_async_data_free (ClutterTextureAsyncData *data)
{
/* This function should only be called either from the main thread
once it is known that the load thread has completed or from the
load thread itself if the abort flag is true (in which case the
main thread has disowned the data) */
if (data->load_filename)
g_free (data->load_filename);
if (data->load_bitmap)
cogl_bitmap_free (data->load_bitmap);
if (data->load_error)
g_error_free (data->load_error);
if (data->mutex)
g_mutex_free (data->mutex);
g_slice_free (ClutterTextureAsyncData, data);
}
/*
* clutter_texture_async_load_cancel:
* @texture: a #ClutterTexture
*
* Cancels an asynchronous loading operation, whether done
* with threads enabled or just using the main loop
*/
static void
clutter_texture_async_load_cancel (ClutterTexture *texture)
{
ClutterTexturePrivate *priv = texture->priv;
if (priv->async_data)
{
GMutex *mutex = priv->async_data->mutex;
/* The mutex will only be NULL if the no thread was used for
this load, in which case there's no need for any
synchronization */
if (mutex)
g_mutex_lock (mutex);
/* If there is no thread behind this load then we can just abort
the idle handler and destroy the load data immediately */
if (priv->async_data->load_idle)
{
g_source_remove (priv->async_data->load_idle);
priv->async_data->load_idle = 0;
if (mutex)
g_mutex_unlock (mutex);
clutter_texture_async_data_free (priv->async_data);
}
else
{
/* Otherwise we need to tell the thread to abort and disown
the data */
priv->async_data->abort = TRUE;
if (mutex)
g_mutex_unlock (mutex);
}
priv->async_data = NULL;
}
}
static void
2006-05-29 08:59:36 +00:00
clutter_texture_dispose (GObject *object)
{
ClutterTexture *texture = CLUTTER_TEXTURE (object);
2006-05-29 08:59:36 +00:00
ClutterTexturePrivate *priv;
priv = texture->priv;
2006-05-29 08:59:36 +00:00
/* mark that we are in dispose, so when the parent class'
* dispose implementation will call unrealize on us we'll
* not try to copy back the resources from video memory
* to system memory
*/
if (!priv->in_dispose)
priv->in_dispose = TRUE;
texture_free_gl_resources (texture);
texture_fbo_free_resources (texture);
2006-05-29 08:59:36 +00:00
if (priv->local_data != NULL)
2006-05-29 08:59:36 +00:00
{
g_free (priv->local_data);
priv->local_data = NULL;
2006-05-29 08:59:36 +00:00
}
clutter_texture_async_load_cancel (texture);
G_OBJECT_CLASS (clutter_texture_parent_class)->dispose (object);
}
static void
clutter_texture_finalize (GObject *object)
{
ClutterTexture *texture = CLUTTER_TEXTURE (object);
ClutterTexturePrivate *priv = texture->priv;
if (priv->material != COGL_INVALID_HANDLE)
{
cogl_material_unref (priv->material);
priv->material = COGL_INVALID_HANDLE;
}
G_OBJECT_CLASS (clutter_texture_parent_class)->finalize (object);
2006-05-29 08:59:36 +00:00
}
static void
clutter_texture_set_property (GObject *object,
2006-05-29 08:59:36 +00:00
guint prop_id,
const GValue *value,
2006-05-29 08:59:36 +00:00
GParamSpec *pspec)
{
ClutterTexture *texture;
ClutterTexturePrivate *priv;
texture = CLUTTER_TEXTURE(object);
priv = texture->priv;
switch (prop_id)
2006-05-29 08:59:36 +00:00
{
case PROP_MAX_TILE_WASTE:
clutter_texture_set_max_tile_waste (texture,
g_value_get_int (value));
2006-05-29 08:59:36 +00:00
break;
case PROP_SYNC_SIZE:
priv->sync_actor_size = g_value_get_boolean (value);
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com> Bug #815 - Split up request, allocation, and paint box * clutter/clutter-actor.[ch]: Rework the size allocation, request and paint area. Now ::request_coords() is called ::allocate(), and ::query_coords() has been split into ::get_preferred_width() and ::get_preferred_height(). See the documentation and the layout test on how to implement a container and layout manager with the new API. (#915, based on a patch by Havoc Pennington, Lucas Rocha and Johan Bilien) * clutter/clutter-clone-texture.c: Port CloneTexture to the new size negotiation API; it just means forwarding the requests to the parent texture. * clutter/clutter-deprecated.h: Add deprecated and replaced API. * clutter/clutter-entry.c: Port Entry to the new size negotiation API. * clutter/clutter-group.c: Port Group to the new size negotiation API; the semantics of the Group actor do not change. * clutter/clutter-label.c: Port Label to the new size negotiation API, and vastly simplify the code. * clutter/clutter-main.[ch]: Add API for executing a relayout when needed. * clutter/clutter-private.h: Add new Stage private API. * clutter/clutter-rectangle.c: Update the get_abs_opacity() call to get_paint_opacity(). * clutter/clutter-stage.c: (clutter_stage_get_preferred_width), (clutter_stage_get_preferred_height), (clutter_stage_allocate), (clutter_stage_class_init): Port Stage to the new size negotiation API. * clutter/clutter-texture.c: Port Texture to the new size negotiation API. * clutter/clutter-types.h: Add ClutterRequestMode enumeration. * clutter/x11/clutter-stage-x11.c: Port the X11 stage implementation to the new size negotiation API. * tests/Makefile.am: Add the layout manager test case. * tests/test-opacity.c: Update. * tests/test-project.c: Update. * tests/test-layout.c: Test case for a layout manager implemented using the new size negotiation API; the layout manager handles both transformed and untransformed children.
2008-06-10 17:07:52 +00:00
clutter_actor_queue_relayout (CLUTTER_ACTOR (texture));
2006-05-29 08:59:36 +00:00
break;
case PROP_REPEAT_X:
if (priv->repeat_x != g_value_get_boolean (value))
{
priv->repeat_x = !priv->repeat_x;
if (CLUTTER_ACTOR_IS_VISIBLE (texture))
clutter_actor_queue_redraw (CLUTTER_ACTOR (texture));
}
2006-05-29 08:59:36 +00:00
break;
case PROP_REPEAT_Y:
if (priv->repeat_y != g_value_get_boolean (value))
{
priv->repeat_y = !priv->repeat_y;
if (CLUTTER_ACTOR_IS_VISIBLE (texture))
clutter_actor_queue_redraw (CLUTTER_ACTOR (texture));
}
2006-05-29 08:59:36 +00:00
break;
case PROP_FILTER_QUALITY:
clutter_texture_set_filter_quality (texture,
g_value_get_enum (value));
break;
case PROP_COGL_TEXTURE:
clutter_texture_set_cogl_texture
(texture, (CoglHandle) g_value_get_boxed (value));
break;
#if EXPOSE_COGL_MATERIAL_PROP
Fully integrates CoglMaterial throughout the rest of Cogl This glues CoglMaterial in as the fundamental way that Cogl describes how to fill in geometry. It adds cogl_set_source (), which is used to set the material which will be used by all subsequent drawing functions It adds cogl_set_source_texture as a convenience for setting up a default material with a single texture layer, and cogl_set_source_color is now also a convenience for setting up a material with a solid fill. "drawing functions" include, cogl_rectangle, cogl_texture_rectangle, cogl_texture_multiple_rectangles, cogl_texture_polygon (though the cogl_texture_* funcs have been renamed; see below for details), cogl_path_fill/stroke and cogl_vertex_buffer_draw*. cogl_texture_rectangle, cogl_texture_multiple_rectangles and cogl_texture_polygon no longer take a texture handle; instead the current source material is referenced. The functions have also been renamed to: cogl_rectangle_with_texture_coords, cogl_rectangles_with_texture_coords and cogl_polygon respectivly. Most code that previously did: cogl_texture_rectangle (tex_handle, x, y,...); needs to be changed to now do: cogl_set_source_texture (tex_handle); cogl_rectangle_with_texture_coords (x, y,....); In the less likely case where you were blending your source texture with a color like: cogl_set_source_color4ub (r,g,b,a); /* where r,g,b,a isn't just white */ cogl_texture_rectangle (tex_handle, x, y,...); you will need your own material to do that: mat = cogl_material_new (); cogl_material_set_color4ub (r,g,b,a); cogl_material_set_layer (mat, 0, tex_handle)); cogl_set_source_material (mat); Code that uses the texture coordinates, 0, 0, 1, 1 don't need to use cog_rectangle_with_texure_coords since these are the coordinates that cogl_rectangle will use. For cogl_texture_polygon; as well as dropping the texture handle, the n_vertices and vertices arguments were transposed for consistency. So code previously written as: cogl_texture_polygon (tex_handle, 3, verts, TRUE); need to be written as: cogl_set_source_texture (tex_handle); cogl_polygon (verts, 3, TRUE); All of the unit tests have been updated to now use the material API and test-cogl-material has been renamed to test-cogl-multitexture since any textured quad is now technically a test of CoglMaterial but this test specifically creates a material with multiple texture layers. Note: The GLES backend has not been updated yet; that will be done in a following commit.
2009-01-23 16:15:40 +00:00
case PROP_COGL_MATERIAL:
clutter_texture_set_cogl_material
(texture, (CoglHandle) g_value_get_boxed (value));
break;
#endif
case PROP_FILENAME:
clutter_texture_set_from_file (texture,
g_value_get_string (value),
NULL);
break;
case PROP_NO_SLICE:
priv->no_slice = g_value_get_boolean (value);
break;
case PROP_KEEP_ASPECT_RATIO:
priv->keep_aspect_ratio = g_value_get_boolean (value);
break;
2009-03-11 18:26:30 +00:00
case PROP_LOAD_DATA_ASYNC:
if (g_value_get_boolean (value))
{
priv->load_async_set = TRUE;
priv->load_data_async = TRUE;
}
2009-03-11 18:26:30 +00:00
break;
case PROP_LOAD_ASYNC:
if (g_value_get_boolean (value))
{
priv->load_data_async = TRUE;
priv->load_async_set = TRUE;
priv->load_size_async = TRUE;
}
break;
2006-05-29 08:59:36 +00:00
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clutter_texture_get_property (GObject *object,
2006-05-29 08:59:36 +00:00
guint prop_id,
GValue *value,
2006-05-29 08:59:36 +00:00
GParamSpec *pspec)
{
ClutterTexture *texture;
ClutterTexturePrivate *priv;
CoglHandle cogl_texture;
2006-05-29 08:59:36 +00:00
texture = CLUTTER_TEXTURE(object);
priv = texture->priv;
switch (prop_id)
2006-05-29 08:59:36 +00:00
{
case PROP_MAX_TILE_WASTE:
g_value_set_int (value, clutter_texture_get_max_tile_waste (texture));
2006-05-29 08:59:36 +00:00
break;
case PROP_PIXEL_FORMAT:
cogl_texture = clutter_texture_get_cogl_texture (texture);
if (cogl_texture == COGL_INVALID_HANDLE)
g_value_set_int (value, COGL_PIXEL_FORMAT_ANY);
else
g_value_set_int (value, cogl_texture_get_format (cogl_texture));
2006-05-29 08:59:36 +00:00
break;
case PROP_SYNC_SIZE:
g_value_set_boolean (value, priv->sync_actor_size);
2006-05-29 08:59:36 +00:00
break;
case PROP_REPEAT_X:
g_value_set_boolean (value, priv->repeat_x);
break;
case PROP_REPEAT_Y:
g_value_set_boolean (value, priv->repeat_y);
break;
case PROP_FILTER_QUALITY:
g_value_set_enum (value, clutter_texture_get_filter_quality (texture));
break;
case PROP_COGL_TEXTURE:
g_value_set_boxed (value, clutter_texture_get_cogl_texture (texture));
break;
case PROP_COGL_MATERIAL:
g_value_set_boxed (value, clutter_texture_get_cogl_material (texture));
break;
case PROP_NO_SLICE:
g_value_set_boolean (value, priv->no_slice);
break;
case PROP_KEEP_ASPECT_RATIO:
g_value_set_boolean (value, priv->keep_aspect_ratio);
break;
2006-05-29 08:59:36 +00:00
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
2006-05-29 08:59:36 +00:00
}
static void
clutter_texture_class_init (ClutterTextureClass *klass)
{
GObjectClass *gobject_class;
ClutterActorClass *actor_class;
2006-05-29 08:59:36 +00:00
gobject_class = (GObjectClass*) klass;
actor_class = (ClutterActorClass*) klass;
g_type_class_add_private (klass, sizeof (ClutterTexturePrivate));
2006-05-29 08:59:36 +00:00
actor_class->paint = clutter_texture_paint;
actor_class->realize = clutter_texture_realize;
actor_class->unrealize = clutter_texture_unrealize;
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com> Bug #815 - Split up request, allocation, and paint box * clutter/clutter-actor.[ch]: Rework the size allocation, request and paint area. Now ::request_coords() is called ::allocate(), and ::query_coords() has been split into ::get_preferred_width() and ::get_preferred_height(). See the documentation and the layout test on how to implement a container and layout manager with the new API. (#915, based on a patch by Havoc Pennington, Lucas Rocha and Johan Bilien) * clutter/clutter-clone-texture.c: Port CloneTexture to the new size negotiation API; it just means forwarding the requests to the parent texture. * clutter/clutter-deprecated.h: Add deprecated and replaced API. * clutter/clutter-entry.c: Port Entry to the new size negotiation API. * clutter/clutter-group.c: Port Group to the new size negotiation API; the semantics of the Group actor do not change. * clutter/clutter-label.c: Port Label to the new size negotiation API, and vastly simplify the code. * clutter/clutter-main.[ch]: Add API for executing a relayout when needed. * clutter/clutter-private.h: Add new Stage private API. * clutter/clutter-rectangle.c: Update the get_abs_opacity() call to get_paint_opacity(). * clutter/clutter-stage.c: (clutter_stage_get_preferred_width), (clutter_stage_get_preferred_height), (clutter_stage_allocate), (clutter_stage_class_init): Port Stage to the new size negotiation API. * clutter/clutter-texture.c: Port Texture to the new size negotiation API. * clutter/clutter-types.h: Add ClutterRequestMode enumeration. * clutter/x11/clutter-stage-x11.c: Port the X11 stage implementation to the new size negotiation API. * tests/Makefile.am: Add the layout manager test case. * tests/test-opacity.c: Update. * tests/test-project.c: Update. * tests/test-layout.c: Test case for a layout manager implemented using the new size negotiation API; the layout manager handles both transformed and untransformed children.
2008-06-10 17:07:52 +00:00
actor_class->get_preferred_width = clutter_texture_get_preferred_width;
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com> Bug #815 - Split up request, allocation, and paint box * clutter/clutter-actor.[ch]: Rework the size allocation, request and paint area. Now ::request_coords() is called ::allocate(), and ::query_coords() has been split into ::get_preferred_width() and ::get_preferred_height(). See the documentation and the layout test on how to implement a container and layout manager with the new API. (#915, based on a patch by Havoc Pennington, Lucas Rocha and Johan Bilien) * clutter/clutter-clone-texture.c: Port CloneTexture to the new size negotiation API; it just means forwarding the requests to the parent texture. * clutter/clutter-deprecated.h: Add deprecated and replaced API. * clutter/clutter-entry.c: Port Entry to the new size negotiation API. * clutter/clutter-group.c: Port Group to the new size negotiation API; the semantics of the Group actor do not change. * clutter/clutter-label.c: Port Label to the new size negotiation API, and vastly simplify the code. * clutter/clutter-main.[ch]: Add API for executing a relayout when needed. * clutter/clutter-private.h: Add new Stage private API. * clutter/clutter-rectangle.c: Update the get_abs_opacity() call to get_paint_opacity(). * clutter/clutter-stage.c: (clutter_stage_get_preferred_width), (clutter_stage_get_preferred_height), (clutter_stage_allocate), (clutter_stage_class_init): Port Stage to the new size negotiation API. * clutter/clutter-texture.c: Port Texture to the new size negotiation API. * clutter/clutter-types.h: Add ClutterRequestMode enumeration. * clutter/x11/clutter-stage-x11.c: Port the X11 stage implementation to the new size negotiation API. * tests/Makefile.am: Add the layout manager test case. * tests/test-opacity.c: Update. * tests/test-project.c: Update. * tests/test-layout.c: Test case for a layout manager implemented using the new size negotiation API; the layout manager handles both transformed and untransformed children.
2008-06-10 17:07:52 +00:00
actor_class->get_preferred_height = clutter_texture_get_preferred_height;
actor_class->allocate = clutter_texture_allocate;
2006-05-29 08:59:36 +00:00
gobject_class->dispose = clutter_texture_dispose;
gobject_class->finalize = clutter_texture_finalize;
2006-05-29 08:59:36 +00:00
gobject_class->set_property = clutter_texture_set_property;
gobject_class->get_property = clutter_texture_get_property;
g_object_class_install_property
(gobject_class, PROP_SYNC_SIZE,
g_param_spec_boolean ("sync-size",
"Sync size of actor",
"Auto sync size of actor to underlying pixbuf "
"dimensions",
2006-05-29 08:59:36 +00:00
TRUE,
CLUTTER_PARAM_READWRITE));
2006-05-29 08:59:36 +00:00
g_object_class_install_property
(gobject_class, PROP_NO_SLICE,
g_param_spec_boolean ("disable-slicing",
"Disable Slicing",
"Force the underlying texture to be singlular"
"and not made of of smaller space saving "
"inidivual textures.",
FALSE,
G_PARAM_CONSTRUCT_ONLY | CLUTTER_PARAM_READWRITE));
2006-05-29 08:59:36 +00:00
g_object_class_install_property
(gobject_class, PROP_REPEAT_X,
g_param_spec_boolean ("repeat-x",
"Tile underlying pixbuf in x direction",
"Repeat underlying pixbuf rather than scale "
"in x direction.",
2006-05-29 08:59:36 +00:00
FALSE,
CLUTTER_PARAM_READWRITE));
2006-05-29 08:59:36 +00:00
g_object_class_install_property
(gobject_class, PROP_REPEAT_Y,
g_param_spec_boolean ("repeat-y",
"Tile underlying pixbuf in y direction",
"Repeat underlying pixbuf rather than scale "
"in y direction.",
2006-05-29 08:59:36 +00:00
FALSE,
CLUTTER_PARAM_READWRITE));
2006-05-29 08:59:36 +00:00
g_object_class_install_property
(gobject_class, PROP_FILTER_QUALITY,
g_param_spec_enum ("filter-quality",
"Filter Quality",
"Rendering quality used when drawing the texture.",
CLUTTER_TYPE_TEXTURE_QUALITY,
CLUTTER_TEXTURE_QUALITY_MEDIUM,
G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE));
2006-05-29 08:59:36 +00:00
g_object_class_install_property
(gobject_class, PROP_MAX_TILE_WASTE,
g_param_spec_int ("tile-waste",
"Tile dimension to waste",
"Max wastage dimension of a texture when using "
"sliced textures or -1 to disable slicing. "
"Bigger values use less textures, "
"smaller values less texture memory.",
-1,
2006-05-29 08:59:36 +00:00
G_MAXINT,
63,
G_PARAM_CONSTRUCT_ONLY | CLUTTER_PARAM_READWRITE));
2006-05-29 08:59:36 +00:00
g_object_class_install_property
(gobject_class, PROP_PIXEL_FORMAT,
g_param_spec_int ("pixel-format",
"Texture pixel format",
"CoglPixelFormat to use.",
2006-05-29 08:59:36 +00:00
0,
G_MAXINT,
COGL_PIXEL_FORMAT_RGBA_8888,
G_PARAM_READABLE));
2006-05-29 08:59:36 +00:00
g_object_class_install_property
(gobject_class, PROP_COGL_TEXTURE,
g_param_spec_boxed ("cogl-texture",
"COGL Texture",
"The underlying COGL texture handle used to draw "
"this actor",
COGL_TYPE_HANDLE,
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class, PROP_COGL_MATERIAL,
g_param_spec_boxed ("cogl-material",
"COGL Material",
"The underlying COGL material handle used to draw "
"this actor",
COGL_TYPE_HANDLE,
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class, PROP_FILENAME,
g_param_spec_string ("filename",
"Filename",
"The full path of the file containing the texture",
NULL,
G_PARAM_WRITABLE));
g_object_class_install_property
(gobject_class, PROP_KEEP_ASPECT_RATIO,
g_param_spec_boolean ("keep-aspect-ratio",
"Keep Aspect Ratio",
"Keep the aspect ratio of the texture when "
"requesting the preferred width or height",
FALSE,
CLUTTER_PARAM_READWRITE));
/**
* ClutterTexture:load-async:
*
* Tries to load a texture from a filename by using a local thread to perform
* the read operations. The initially created texture has dimensions 0x0 when
* the true size becomes available the #ClutterTexture::size-change signal is
* emitted and when the image has completed loading the
* #ClutterTexture::load-finished signal is emitted.
*
* Threading is only enabled if g_thread_init() has been called prior to
* clutter_init(), otherwise #ClutterTexture will use the main loop to load
* the image.
*
* The upload of the texture data on the GL pipeline is not asynchronous, as
* it must be performed from within the same thread that called
* clutter_main().
*
* Since: 1.0
*/
2009-03-11 18:26:30 +00:00
g_object_class_install_property
(gobject_class, PROP_LOAD_ASYNC,
g_param_spec_boolean ("load-async",
"Load asynchronously",
2009-03-11 18:26:30 +00:00
"Load files inside a thread to avoid blocking when "
"loading images.",
FALSE,
CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
2009-03-11 18:26:30 +00:00
/**
* ClutterTexture:load-data-async:
2009-03-11 18:26:30 +00:00
*
* Like #ClutterTexture:load-async but loads the width and height
* synchronously causing some blocking.
2009-03-11 18:26:30 +00:00
*
* Since: 1.0
*/
g_object_class_install_property
(gobject_class, PROP_LOAD_DATA_ASYNC,
g_param_spec_boolean ("load-data-async",
"Load data asynchronously",
"Decode image data files inside a thread to reduce "
"blocking when loading images.",
FALSE,
CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
/**
* ClutterTexture::size-change:
* @texture: the texture which received the signal
* @width: the width of the new texture
* @height: the height of the new texture
*
* The ::size-change signal is emitted each time the size of the
* pixbuf used by @texture changes. The new size is given as
* argument to the callback.
*/
texture_signals[SIZE_CHANGE] =
2006-05-29 08:59:36 +00:00
g_signal_new ("size-change",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterTextureClass, size_change),
NULL, NULL,
clutter_marshal_VOID__INT_INT,
G_TYPE_NONE,
2006-05-29 08:59:36 +00:00
2, G_TYPE_INT, G_TYPE_INT);
/**
* ClutterTexture::pixbuf-change:
* @texture: the texture which received the signal
*
* The ::pixbuf-change signal is emitted each time the pixbuf
* used by @texture changes.
*/
texture_signals[PIXBUF_CHANGE] =
2006-05-29 08:59:36 +00:00
g_signal_new ("pixbuf-change",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterTextureClass, pixbuf_change),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
/**
* ClutterTexture::load-finished:
* @texture: the texture which received the signal
* @error: A set error, or %NULL
*
* The ::load-finished signal is emitted when a texture load has
* completed. If there was an error during loading, @error will
* be set, otherwise it will be %NULL
*
* Since: 1.0
*/
texture_signals[LOAD_FINISHED] =
g_signal_new (I_("load-finished"),
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterTextureClass, load_finished),
NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE,
1,
G_TYPE_POINTER);
2006-05-29 08:59:36 +00:00
}
static ClutterScriptableIface *parent_scriptable_iface = NULL;
static void
clutter_texture_set_custom_property (ClutterScriptable *scriptable,
ClutterScript *script,
const gchar *name,
const GValue *value)
{
ClutterTexture *texture = CLUTTER_TEXTURE (scriptable);
if (strcmp ("filename", name) == 0)
{
const gchar *str = g_value_get_string (value);
gchar *path;
GError *error;
path = clutter_script_lookup_filename (script, str);
if (G_UNLIKELY (!path))
return;
error = NULL;
clutter_texture_set_from_file (texture, path, &error);
if (error)
{
g_warning ("Unable to open image path at `%s': %s",
path,
error->message);
g_error_free (error);
}
g_free (path);
}
else
{
/* chain up */
if (parent_scriptable_iface->set_custom_property)
parent_scriptable_iface->set_custom_property (scriptable, script,
name,
value);
}
}
static void
clutter_scriptable_iface_init (ClutterScriptableIface *iface)
{
parent_scriptable_iface = g_type_interface_peek_parent (iface);
if (!parent_scriptable_iface)
parent_scriptable_iface = g_type_default_interface_peek
(CLUTTER_TYPE_SCRIPTABLE);
iface->set_custom_property = clutter_texture_set_custom_property;
}
2006-05-29 08:59:36 +00:00
static void
clutter_texture_init (ClutterTexture *self)
{
ClutterTexturePrivate *priv;
self->priv = priv = CLUTTER_TEXTURE_GET_PRIVATE (self);
priv->max_tile_waste = 63;
priv->filter_quality = CLUTTER_TEXTURE_QUALITY_MEDIUM;
priv->repeat_x = FALSE;
priv->repeat_y = FALSE;
priv->sync_actor_size = TRUE;
priv->material = cogl_material_new ();
priv->fbo_texture = COGL_INVALID_HANDLE;
priv->fbo_handle = COGL_INVALID_HANDLE;
priv->local_data = NULL;
priv->keep_aspect_ratio = FALSE;
2006-05-29 08:59:36 +00:00
}
static void
clutter_texture_save_to_local_data (ClutterTexture *texture)
{
ClutterTexturePrivate *priv;
int bpp;
CoglPixelFormat pixel_format;
CoglHandle cogl_texture;
priv = texture->priv;
if (priv->local_data)
{
g_free (priv->local_data);
priv->local_data = NULL;
}
if (priv->material == COGL_INVALID_HANDLE)
return;
cogl_texture = clutter_texture_get_cogl_texture (texture);
priv->local_data_width = cogl_texture_get_width (cogl_texture);
priv->local_data_height = cogl_texture_get_height (cogl_texture);
pixel_format = cogl_texture_get_format (cogl_texture);
priv->local_data_has_alpha = pixel_format & COGL_A_BIT;
bpp = priv->local_data_has_alpha ? 4 : 3;
/* Align to 4 bytes */
priv->local_data_rowstride = (priv->local_data_width * bpp + 3) & ~3;
/* Store the filter quality and max_tile_waste from the texture
properties so that they will be restored the data is loaded
again */
priv->max_tile_waste = clutter_texture_get_max_tile_waste (texture);
priv->filter_quality = clutter_texture_get_filter_quality (texture);
priv->local_data = g_malloc (priv->local_data_rowstride
* priv->local_data_height);
if (cogl_texture_get_data (cogl_texture,
priv->local_data_has_alpha
? COGL_PIXEL_FORMAT_RGBA_8888
: COGL_PIXEL_FORMAT_RGB_888,
priv->local_data_rowstride,
priv->local_data) == 0)
{
g_free (priv->local_data);
priv->local_data = NULL;
}
}
static void
clutter_texture_load_from_local_data (ClutterTexture *texture)
{
ClutterTexturePrivate *priv;
priv = texture->priv;
if (priv->local_data == NULL)
return;
clutter_texture_set_from_rgb_data (texture,
priv->local_data,
priv->local_data_has_alpha,
priv->local_data_width,
priv->local_data_height,
priv->local_data_rowstride,
priv->local_data_has_alpha ? 4: 3,
0, NULL);
g_free (priv->local_data);
priv->local_data = NULL;
}
/**
* clutter_texture_get_cogl_material:
* @texture: A #ClutterTexture
*
* Returns a handle to the underlying COGL material used for drawing
* the actor. No extra reference is taken so if you need to keep the
* handle then you should call cogl_material_ref() on it.
*
* Since: 1.0
*
* Return value: COGL material handle
*/
CoglHandle
clutter_texture_get_cogl_material (ClutterTexture *texture)
{
g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), COGL_INVALID_HANDLE);
return texture->priv->material;
}
/**
* clutter_texture_set_cogl_material:
* @texture: A #ClutterTexture
* @cogl_material: A CoglHandle for a material
*
* Replaces the underlying COGL texture drawn by this actor with
* @cogl_tex. A reference to the texture is taken so if the handle is
* no longer needed it should be deref'd with cogl_texture_unref.
*
* Since: 0.8
*
*/
void
clutter_texture_set_cogl_material (ClutterTexture *texture,
CoglHandle cogl_material)
{
CoglHandle cogl_texture;
g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
/* This */
if (texture->priv->material)
cogl_material_unref (texture->priv->material);
texture->priv->material = cogl_material;
/* XXX: We are re-asserting the first layer of the new material to ensure the
* priv state is in sync with the contents of the material. */
cogl_texture = clutter_texture_get_cogl_texture (texture);
clutter_texture_set_cogl_texture (texture, cogl_texture);
/* XXX: If we add support for more material layers, this will need
* extending */
}
2006-05-29 08:59:36 +00:00
/**
* clutter_texture_get_cogl_texture
* @texture: A #ClutterTexture
2006-05-29 08:59:36 +00:00
*
* Retrieves the handle to the underlying COGL texture used for drawing
* the actor. No extra reference is taken so if you need to keep the
* handle then you should call cogl_texture_ref() on it.
*
* The texture handle returned is the first layer of the material
* handle used by the #ClutterTexture. If you need to access the other
* layers you should use clutter_texture_get_cogl_material() instead
* and use the #CoglMaterial API.
2006-05-29 08:59:36 +00:00
*
* Since: 0.8
*
* Return value: COGL texture handle
*/
CoglHandle
clutter_texture_get_cogl_texture (ClutterTexture *texture)
2006-05-29 08:59:36 +00:00
{
const GList *layers;
int n_layers;
g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), COGL_INVALID_HANDLE);
layers = cogl_material_get_layers (texture->priv->material);
n_layers = g_list_length ((GList *)layers);
if (n_layers == 0)
return COGL_INVALID_HANDLE;
return cogl_material_layer_get_texture (layers->data);
}
/**
* clutter_texture_set_cogl_texture
* @texture: A #ClutterTexture
* @cogl_tex: A CoglHandle for a texture
*
* Replaces the underlying COGL texture drawn by this actor with
* @cogl_tex. A reference to the texture is taken so if the handle is
* no longer needed it should be deref'd with cogl_texture_unref.
*
* Since: 0.8
*/
void
clutter_texture_set_cogl_texture (ClutterTexture *texture,
CoglHandle cogl_tex)
{
ClutterTexturePrivate *priv;
gboolean size_change;
guint width, height;
g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
g_return_if_fail (cogl_is_texture (cogl_tex));
priv = texture->priv;
width = cogl_texture_get_width (cogl_tex);
height = cogl_texture_get_height (cogl_tex);
/* Reference the new texture now in case it is the same one we are
already using */
cogl_texture_ref (cogl_tex);
/* Remove FBO if exisiting */
if (priv->fbo_source)
texture_fbo_free_resources (texture);
/* Remove old texture */
texture_free_gl_resources (texture);
/* Use the new texture */
cogl_material_set_layer (priv->material, 0, cogl_tex);
/* The material now holds a reference to the texture so we can
safely release the reference we claimed above */
cogl_texture_unref (cogl_tex);
size_change = width != priv->width || height != priv->height;
priv->width = width;
priv->height = height;
CLUTTER_NOTE (TEXTURE, "set size %ix%i\n",
priv->width,
priv->height);
CLUTTER_ACTOR_SET_FLAGS (CLUTTER_ACTOR (texture), CLUTTER_ACTOR_REALIZED);
if (size_change)
{
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com> Bug #815 - Split up request, allocation, and paint box * clutter/clutter-actor.[ch]: Rework the size allocation, request and paint area. Now ::request_coords() is called ::allocate(), and ::query_coords() has been split into ::get_preferred_width() and ::get_preferred_height(). See the documentation and the layout test on how to implement a container and layout manager with the new API. (#915, based on a patch by Havoc Pennington, Lucas Rocha and Johan Bilien) * clutter/clutter-clone-texture.c: Port CloneTexture to the new size negotiation API; it just means forwarding the requests to the parent texture. * clutter/clutter-deprecated.h: Add deprecated and replaced API. * clutter/clutter-entry.c: Port Entry to the new size negotiation API. * clutter/clutter-group.c: Port Group to the new size negotiation API; the semantics of the Group actor do not change. * clutter/clutter-label.c: Port Label to the new size negotiation API, and vastly simplify the code. * clutter/clutter-main.[ch]: Add API for executing a relayout when needed. * clutter/clutter-private.h: Add new Stage private API. * clutter/clutter-rectangle.c: Update the get_abs_opacity() call to get_paint_opacity(). * clutter/clutter-stage.c: (clutter_stage_get_preferred_width), (clutter_stage_get_preferred_height), (clutter_stage_allocate), (clutter_stage_class_init): Port Stage to the new size negotiation API. * clutter/clutter-texture.c: Port Texture to the new size negotiation API. * clutter/clutter-types.h: Add ClutterRequestMode enumeration. * clutter/x11/clutter-stage-x11.c: Port the X11 stage implementation to the new size negotiation API. * tests/Makefile.am: Add the layout manager test case. * tests/test-opacity.c: Update. * tests/test-project.c: Update. * tests/test-layout.c: Test case for a layout manager implemented using the new size negotiation API; the layout manager handles both transformed and untransformed children.
2008-06-10 17:07:52 +00:00
g_signal_emit (texture, texture_signals[SIZE_CHANGE], 0,
priv->width,
priv->height);
if (priv->sync_actor_size)
clutter_actor_queue_relayout (CLUTTER_ACTOR (texture));
}
/* rename signal */
g_signal_emit (texture, texture_signals[PIXBUF_CHANGE], 0);
g_object_notify (G_OBJECT (texture), "cogl-texture");
/* If resized actor may need resizing but paint() will do this */
if (CLUTTER_ACTOR_IS_VISIBLE (texture))
clutter_actor_queue_redraw (CLUTTER_ACTOR (texture));
2006-05-29 08:59:36 +00:00
}
static gboolean
clutter_texture_set_from_data (ClutterTexture *texture,
const guchar *data,
CoglPixelFormat source_format,
gint width,
gint height,
gint rowstride,
gint bpp,
GError **error)
{
ClutterTexturePrivate *priv = texture->priv;
CoglHandle new_texture = COGL_INVALID_HANDLE;
CoglTextureFlags flags = COGL_TEXTURE_NONE;
gint min_filter, mag_filter;
gint max_waste = -1;
if (!priv->no_slice)
max_waste = priv->max_tile_waste;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
new_texture = cogl_texture_new_from_data (width, height,
max_waste, flags,
source_format,
COGL_PIXEL_FORMAT_ANY,
rowstride,
data);
if (G_UNLIKELY (new_texture == COGL_INVALID_HANDLE))
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
"Failed to create COGL texture");
return FALSE;
}
clutter_texture_quality_to_filters (priv->filter_quality,
&min_filter,
&mag_filter);
cogl_texture_set_filters (new_texture, min_filter, mag_filter);
clutter_texture_set_cogl_texture (texture, new_texture);
cogl_texture_unref (new_texture);
g_signal_emit (texture, texture_signals[LOAD_FINISHED], 0, error);
return TRUE;
}
2006-05-29 08:59:36 +00:00
/**
* clutter_texture_set_from_rgb_data:
* @texture: A #ClutterTexture
* @data: Image data in RGBA type colorspace.
* @has_alpha: Set to TRUE if image data has an 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 3 and 4 supported,
* depending on @has_alpha)
* @flags: #ClutterTextureFlags
2007-12-24 16:24:26 +00:00
* @error: return location for a #GError, or %NULL.
2006-05-29 08:59:36 +00:00
*
* Sets #ClutterTexture image data.
2006-05-29 08:59:36 +00:00
*
2007-12-24 16:24:26 +00:00
* Note: This function is likely to change in future versions.
*
2007-12-24 16:24:26 +00:00
* Return value: %TRUE on success, %FALSE on failure.
*
* Since: 0.4.
2006-05-29 08:59:36 +00:00
**/
gboolean
clutter_texture_set_from_rgb_data (ClutterTexture *texture,
const guchar *data,
gboolean has_alpha,
gint width,
gint height,
gint rowstride,
gint bpp,
ClutterTextureFlags flags,
GError **error)
2006-05-29 08:59:36 +00:00
{
ClutterTexturePrivate *priv;
CoglPixelFormat source_format;
2006-05-29 08:59:36 +00:00
g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), FALSE);
priv = texture->priv;
/* Convert the flags to a CoglPixelFormat */
if (has_alpha)
{
if (bpp != 4)
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
"Unsupported BPP");
return FALSE;
}
source_format = COGL_PIXEL_FORMAT_RGBA_8888;
}
else
{
if (bpp != 3)
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
"Unsupported BPP");
return FALSE;
}
source_format = COGL_PIXEL_FORMAT_RGB_888;
}
if ((flags & CLUTTER_TEXTURE_RGB_FLAG_BGR))
source_format |= COGL_BGR_BIT;
if ((flags & CLUTTER_TEXTURE_RGB_FLAG_PREMULT))
source_format |= COGL_PREMULT_BIT;
return clutter_texture_set_from_data (texture, data,
source_format,
width, height,
rowstride, bpp,
error);
}
/**
* clutter_texture_set_from_yuv_data:
* @texture: A #ClutterTexture
* @data: Image data in YUV type colorspace.
* @width: Width in pixels of image data.
* @height: Height in pixels of image data
* @flags: #ClutterTextureFlags
* @error: Return location for a #GError, or %NULL.
*
* Sets a #ClutterTexture from YUV image data. If an error occurred,
* %FALSE is returned and @error is set.
*
* This function is likely to change in future versions.
*
* Return value: %TRUE if the texture was successfully updated
*
* Since: 0.4
*/
gboolean
clutter_texture_set_from_yuv_data (ClutterTexture *texture,
const guchar *data,
gint width,
gint height,
ClutterTextureFlags flags,
GError **error)
{
ClutterTexturePrivate *priv;
g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), 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;
/* Convert the flags to a CoglPixelFormat */
if ((flags & CLUTTER_TEXTURE_YUV_FLAG_YUV2))
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
"YUV2 not supported");
return FALSE;
}
return clutter_texture_set_from_data (texture, data,
COGL_PIXEL_FORMAT_YUV,
width, height,
width * 3, 3,
error);
}
/*
* clutter_texture_async_load_complete:
* @self: a #ClutterTexture
* @bitmap: a #CoglBitmap
* @error: load error
*
* If @error is %NULL, loads @bitmap into a #CoglTexture.
*
* This function emits the ::load-finished signal on @self.
*/
static void
clutter_texture_async_load_complete (ClutterTexture *self,
CoglBitmap *bitmap,
const GError *error)
{
ClutterTexturePrivate *priv = self->priv;
CoglHandle handle;
CoglTextureFlags flags = COGL_TEXTURE_NONE;
gint waste = -1;
priv->async_data = NULL;
if (error == NULL)
{
if (!priv->no_slice)
waste = priv->max_tile_waste;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
handle = cogl_texture_new_from_bitmap (bitmap,
waste, flags,
COGL_PIXEL_FORMAT_ANY);
clutter_texture_set_cogl_texture (self, handle);
if (priv->load_size_async)
{
g_signal_emit (self, texture_signals[SIZE_CHANGE], 0,
cogl_texture_get_width(handle),
cogl_texture_get_height (handle));
}
cogl_texture_unref (handle);
}
g_signal_emit (self, texture_signals[LOAD_FINISHED], 0, error);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
}
static gboolean
clutter_texture_thread_idle_func (gpointer user_data)
{
ClutterTextureAsyncData *data = user_data;
/* Grab the mutex so we can be sure the thread has unlocked it
before we destroy it */
g_mutex_lock (data->mutex);
g_mutex_unlock (data->mutex);
clutter_texture_async_load_complete (data->texture, data->load_bitmap,
data->load_error);
clutter_texture_async_data_free (data);
return FALSE;
}
static void
clutter_texture_thread_func (gpointer user_data, gpointer pool_data)
{
ClutterTextureAsyncData *data = user_data;
gboolean should_abort;
/* Make sure we haven't been told to abort before the thread had a
chance to run */
g_mutex_lock (data->mutex);
should_abort = data->abort;
g_mutex_unlock (data->mutex);
if (should_abort)
{
/* If we've been told to abort then main thread has disowned the
async data and we need to free it */
clutter_texture_async_data_free (data);
return;
}
data->load_bitmap = cogl_bitmap_new_from_file (data->load_filename,
&data->load_error);
/* Check again if we've been told to abort */
g_mutex_lock (data->mutex);
if (data->abort)
{
g_mutex_unlock (data->mutex);
clutter_texture_async_data_free (data);
}
else
{
/* Make sure we give the image to GL in the main thread, where we
* hold the main Clutter lock. Once load_idle is non-NULL then the
* main thread is guaranteed not to set the abort flag. It can't
* set it while we're holding the mutex so we can safely start the
* idle handler now without the possibility of calling the
* callback after it is aborted */
data->load_idle =
clutter_threads_add_idle_full (G_PRIORITY_LOW, clutter_texture_thread_idle_func, data, NULL);
g_mutex_unlock (data->mutex);
}
return;
}
static gboolean
clutter_texture_idle_func (gpointer user_data)
{
ClutterTextureAsyncData *data = user_data;
GError *internal_error = NULL;
data->load_bitmap = cogl_bitmap_new_from_file (data->load_filename,
&internal_error);
clutter_texture_async_load_complete (data->texture, data->load_bitmap,
internal_error);
if (internal_error)
g_error_free (internal_error);
clutter_texture_async_data_free (data);
return FALSE;
}
/*
* clutter_texture_async_load:
* @self: a #ClutterTExture
* @filename: name of the file to load
* @error: return location for a #GError
*
* Starts an asynchronous load of the file name stored inside
* the load_filename member of @data.
*
* If threading is enabled we use a GThread to perform the actual
* I/O; if threading is not enabled, we use an idle GSource.
*
* The I/O is the only bit done in a thread -- uploading the
* texture data to the GL pipeline must be done from within the
* same thread that called clutter_main(). Threaded upload should
* be part of the GL implementation.
*
* This function will block until we get a size from the file
* so that we can effectively get the size the texture actor after
* clutter_texture_set_from_file().
*
* Return value: %TRUE if the asynchronous loading was successfully
* initiated, %FALSE otherwise
*/
static gboolean
clutter_texture_async_load (ClutterTexture *self,
const gchar *filename,
GError **error)
{
ClutterTexturePrivate *priv = self->priv;
ClutterTextureAsyncData *data;
gint width, height;
gboolean res;
/* ask the file for a size; if we cannot get the size then
* there's no point in even continuing the asynchronous
* loading, so we just stop there
*/
2009-03-11 18:26:30 +00:00
if (priv->load_size_async)
{
res = TRUE;
width = 0;
height = 0;
2009-03-11 18:26:30 +00:00
}
else
{
res = cogl_bitmap_get_size_from_file (filename, &width, &height);
}
if (!res)
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
"Failed to create COGL texture");
return FALSE;
}
else
{
priv->width = width;
priv->height = height;
}
clutter_texture_async_load_cancel (self);
data = g_slice_new (ClutterTextureAsyncData);
data->abort = FALSE;
data->texture = self;
data->load_idle = 0;
data->load_filename = g_strdup (filename);
data->load_bitmap = NULL;
data->load_error = NULL;
priv->async_data = data;
if (g_thread_supported ())
{
data->mutex = g_mutex_new ();
if (async_thread_pool == NULL)
/* This apparently can't fail if exclusive == FALSE */
async_thread_pool
= g_thread_pool_new (clutter_texture_thread_func,
NULL, 1, FALSE, NULL);
g_thread_pool_push (async_thread_pool, data, NULL);
}
else
{
data->mutex = NULL;
data->load_idle
= clutter_threads_add_idle (clutter_texture_idle_func, data);
}
return TRUE;
}
/**
* clutter_texture_set_from_file:
* @texture: A #ClutterTexture
* @filename: The filename of the image in GLib file name encoding
* @error: Return location for a #GError, or %NULL
*
* Sets the #ClutterTexture image data from an image file. In case of
* failure, %FALSE is returned and @error is set.
*
* If #ClutterTexture:load-async is set to %TRUE, this function
* will return as soon as possible, and the actual image loading
* from disk will be performed asynchronously. #ClutterTexture::size-change
* will be emitten when the size of the texture is available and
* #ClutterTexture::load-finished will be emitted when the image has been
* loaded or if an error occurred.
*
* Return value: %TRUE if the image was successfully loaded and set
*
* Since: 0.8
*/
gboolean
clutter_texture_set_from_file (ClutterTexture *texture,
const gchar *filename,
GError **error)
{
ClutterTexturePrivate *priv;
CoglHandle new_texture = COGL_INVALID_HANDLE;
GError *internal_error = NULL;
CoglTextureFlags flags = COGL_TEXTURE_NONE;
gint min_filter, mag_filter;
gint max_waste = -1;
priv = texture->priv;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2006-05-29 08:59:36 +00:00
if (priv->load_data_async)
return clutter_texture_async_load (texture, filename, error);
if (!priv->no_slice)
max_waste = priv->max_tile_waste;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
new_texture = cogl_texture_new_from_file (filename,
max_waste, flags,
COGL_PIXEL_FORMAT_ANY,
&internal_error);
if (new_texture == COGL_INVALID_HANDLE)
{
/* If COGL didn't give an error then make one up */
if (internal_error == NULL)
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
"Failed to create COGL texture");
}
else
g_propagate_error (error, internal_error);
g_signal_emit (texture, texture_signals[LOAD_FINISHED], 0, error);
2006-05-29 08:59:36 +00:00
return FALSE;
}
clutter_texture_quality_to_filters (priv->filter_quality,
&min_filter,
&mag_filter);
cogl_texture_set_filters (new_texture, min_filter, mag_filter);
clutter_texture_set_cogl_texture (texture, new_texture);
2006-05-29 08:59:36 +00:00
cogl_texture_unref (new_texture);
2006-05-29 08:59:36 +00:00
g_signal_emit (texture, texture_signals[LOAD_FINISHED], 0, error);
return TRUE;
2006-05-29 08:59:36 +00:00
}
/**
* clutter_texture_set_filter_quality:
* @texture: a #ClutterTexture
* @filter_quality: new filter quality value
2006-05-29 08:59:36 +00:00
*
* Sets the filter quality when scaling a texture. The quality is an
* enumeration currently the following values are supported:
* %CLUTTER_TEXTURE_QUALITY_LOW which is fast but only uses nearest neighbour
* interpolation. %CLUTTER_TEXTURE_QUALITY_MEDIUM which is computationally a
* bit more expensive (bilinear interpolation), and
* %CLUTTER_TEXTURE_QUALITY_HIGH which uses extra texture memory resources to
* improve scaled down rendering as well (by using mipmaps). The default value
* is %CLUTTER_TEXTURE_QUALITY_MEDIUM.
2006-05-29 08:59:36 +00:00
*
* Since: 0.8
*/
2006-05-29 08:59:36 +00:00
void
clutter_texture_set_filter_quality (ClutterTexture *texture,
ClutterTextureQuality filter_quality)
2006-05-29 08:59:36 +00:00
{
ClutterTexturePrivate *priv;
ClutterTextureQuality old_quality;
2006-05-29 08:59:36 +00:00
g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
2006-05-29 08:59:36 +00:00
priv = texture->priv;
old_quality = clutter_texture_get_filter_quality (texture);
if (filter_quality != old_quality)
{
CoglHandle cogl_texture = clutter_texture_get_cogl_texture (texture);
gint min_filter, mag_filter;
priv->filter_quality = filter_quality;
clutter_texture_quality_to_filters (priv->filter_quality,
&min_filter,
&mag_filter);
/* Is this actually needed - causes problems with TFP mipmaps */
if (cogl_texture != COGL_INVALID_HANDLE)
cogl_texture_set_filters (cogl_texture, min_filter, mag_filter);
if ((old_quality == CLUTTER_TEXTURE_QUALITY_HIGH ||
filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) &&
CLUTTER_ACTOR_IS_REALIZED (texture))
{
gboolean was_visible;
was_visible = CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (texture));
clutter_actor_unrealize (CLUTTER_ACTOR (texture));
clutter_actor_realize (CLUTTER_ACTOR (texture));
if (was_visible)
clutter_actor_show (CLUTTER_ACTOR (texture));
}
g_object_notify (G_OBJECT (texture), "filter-quality");
if (CLUTTER_ACTOR_IS_VISIBLE (texture))
clutter_actor_queue_redraw (CLUTTER_ACTOR (texture));
}
2006-05-29 08:59:36 +00:00
}
/**
* clutter_texture_get_filter_quality
* @texture: A #ClutterTexture
2006-05-29 08:59:36 +00:00
*
* Gets the filter quality used when scaling a texture.
2006-05-29 08:59:36 +00:00
*
* Return value: The filter quality value.
*
* Since: 0.8
*/
ClutterTextureQuality
clutter_texture_get_filter_quality (ClutterTexture *texture)
2006-05-29 08:59:36 +00:00
{
ClutterTexturePrivate *priv;
g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), 0);
2006-05-29 08:59:36 +00:00
priv = texture->priv;
2006-05-29 08:59:36 +00:00
return priv->filter_quality;
2006-05-29 08:59:36 +00:00
}
/**
* clutter_texture_set_max_tile_waste
* @texture: A #ClutterTexture
* @max_tile_waste: Maximum amount of waste in pixels or -1
2006-05-29 08:59:36 +00:00
*
* Sets the maximum number of pixels in either axis that can be wasted
* for an individual texture slice. If -1 is specified then the
* texture is forced not to be sliced and the texture creation will
* fail if the hardware can't create a texture large enough.
2006-05-29 08:59:36 +00:00
*
* The value is only used when first creating a texture so changing it
* after the texture data has been set has no effect.
*
* Since: 0.8
*/
2006-05-29 08:59:36 +00:00
void
clutter_texture_set_max_tile_waste (ClutterTexture *texture,
gint max_tile_waste)
2006-05-29 08:59:36 +00:00
{
ClutterTexturePrivate *priv;
CoglHandle cogl_texture;
g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
priv = texture->priv;
cogl_texture = clutter_texture_get_cogl_texture (texture);
2006-05-29 08:59:36 +00:00
/* There's no point in changing the max_tile_waste if the texture
has already been created because it will be overridden with the
value from the texture handle */
if (cogl_texture == COGL_INVALID_HANDLE)
priv->max_tile_waste = max_tile_waste;
2006-05-29 08:59:36 +00:00
}
/**
* clutter_texture_get_max_tile_waste
* @texture: A #ClutterTexture
2006-05-29 08:59:36 +00:00
*
* Gets the maximum waste that will be used when creating a texture or
* -1 if slicing is disabled.
2006-05-29 08:59:36 +00:00
*
* Return value: The maximum waste or -1 if the texture waste is
* unlimited.
*
* Since: 0.8
*/
gint
clutter_texture_get_max_tile_waste (ClutterTexture *texture)
2006-05-29 08:59:36 +00:00
{
ClutterTexturePrivate *priv;
CoglHandle cogl_texture;
g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), 0);
priv = texture->priv;
cogl_texture = clutter_texture_get_cogl_texture (texture);
if (cogl_texture == COGL_INVALID_HANDLE)
return texture->priv->max_tile_waste;
else
/* If we have a valid texture handle then use the value from that
instead */
return cogl_texture_get_max_waste (cogl_texture);
2006-05-29 08:59:36 +00:00
}
/**
* clutter_texture_new_from_file:
* @filename: The name of an image file to load.
* @error: Return locatoin for an error.
2006-05-29 08:59:36 +00:00
*
* Creates a new ClutterTexture actor to display the image contained a
* file. If the image failed to load then NULL is returned and @error
* is set.
2006-05-29 08:59:36 +00:00
*
* Return value: A newly created #ClutterTexture object or NULL on
* error.
2006-05-29 08:59:36 +00:00
*
* Since: 0.8
2006-05-29 08:59:36 +00:00
**/
ClutterActor*
clutter_texture_new_from_file (const gchar *filename,
GError **error)
2006-05-29 08:59:36 +00:00
{
ClutterActor *texture = clutter_texture_new ();
if (!clutter_texture_set_from_file (CLUTTER_TEXTURE (texture),
filename, error))
{
g_object_ref_sink (texture);
g_object_unref (texture);
return NULL;
}
else
return texture;
2006-05-29 08:59:36 +00:00
}
/**
* clutter_texture_new:
2006-05-29 08:59:36 +00:00
*
* Creates a new empty #ClutterTexture object.
2006-05-29 08:59:36 +00:00
*
* Return value: A newly created #ClutterTexture object.
2006-05-29 08:59:36 +00:00
**/
ClutterActor *
clutter_texture_new (void)
2006-05-29 08:59:36 +00:00
{
return g_object_new (CLUTTER_TYPE_TEXTURE, NULL);
2006-05-29 08:59:36 +00:00
}
/**
* clutter_texture_get_base_size:
* @texture: A #ClutterTexture
* @width: Pointer to gint to be populated with width value if non NULL.
* @height: Pointer to gint to be populated with height value if non NULL.
*
* Gets the size in pixels of the untransformed underlying texture pixbuf data.
*
**/
void /* FIXME: rename to get_image_size */
clutter_texture_get_base_size (ClutterTexture *texture,
gint *width,
gint *height)
{
g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
/* Attempt to realize, mainly for subclasses ( such as labels )
* which may not create pixbuf data and thus base size until
* realization happens.
*/
if (!CLUTTER_ACTOR_IS_REALIZED (texture))
clutter_actor_realize (CLUTTER_ACTOR (texture));
if (width)
*width = texture->priv->width;
if (height)
*height = texture->priv->height;
}
/**
* 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 an 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 on source buffer.
* @bpp: bytes per pixel (Currently only 3 and 4 supported,
* depending on @has_alpha)
* @flags: #ClutterTextureFlags
2007-12-24 16:24:26 +00:00
* @error: return location for a #GError, or %NULL
*
* Updates a sub-region of the pixel data in a #ClutterTexture.
*
2007-12-24 16:24:26 +00:00
* Return value: %TRUE on success, %FALSE on failure.
*
* Since: 0.6
2007-12-24 16:24:26 +00:00
*/
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;
CoglPixelFormat source_format;
CoglHandle cogl_texture;
priv = texture->priv;
if (has_alpha)
{
if (bpp != 4)
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
"Unsupported BPP");
return FALSE;
}
source_format = COGL_PIXEL_FORMAT_RGBA_8888;
}
else
{
if (bpp != 3)
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
"Unsupported BPP");
return FALSE;
}
source_format = COGL_PIXEL_FORMAT_RGB_888;
}
if ((flags & CLUTTER_TEXTURE_RGB_FLAG_BGR))
source_format |= COGL_BGR_BIT;
if ((flags & CLUTTER_TEXTURE_RGB_FLAG_PREMULT))
source_format |= COGL_PREMULT_BIT;
clutter_actor_realize (CLUTTER_ACTOR (texture));
cogl_texture = clutter_texture_get_cogl_texture (texture);
if (cogl_texture == COGL_INVALID_HANDLE)
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
"Failed to realize actor");
return FALSE;
}
if (!cogl_texture_set_region (cogl_texture,
0, 0,
x, y, width, height,
width, height,
source_format,
rowstride,
data))
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
"Failed to upload COGL texture data");
return FALSE;
}
/* rename signal */
g_signal_emit (texture, texture_signals[PIXBUF_CHANGE], 0);
if (CLUTTER_ACTOR_IS_VISIBLE (texture))
clutter_actor_queue_redraw (CLUTTER_ACTOR (texture));
return TRUE;
}
static void
on_fbo_source_size_change (GObject *object,
GParamSpec *param_spec,
ClutterTexture *texture)
{
ClutterTexturePrivate *priv = texture->priv;
guint w, h;
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com> Bug #815 - Split up request, allocation, and paint box * clutter/clutter-actor.[ch]: Rework the size allocation, request and paint area. Now ::request_coords() is called ::allocate(), and ::query_coords() has been split into ::get_preferred_width() and ::get_preferred_height(). See the documentation and the layout test on how to implement a container and layout manager with the new API. (#915, based on a patch by Havoc Pennington, Lucas Rocha and Johan Bilien) * clutter/clutter-clone-texture.c: Port CloneTexture to the new size negotiation API; it just means forwarding the requests to the parent texture. * clutter/clutter-deprecated.h: Add deprecated and replaced API. * clutter/clutter-entry.c: Port Entry to the new size negotiation API. * clutter/clutter-group.c: Port Group to the new size negotiation API; the semantics of the Group actor do not change. * clutter/clutter-label.c: Port Label to the new size negotiation API, and vastly simplify the code. * clutter/clutter-main.[ch]: Add API for executing a relayout when needed. * clutter/clutter-private.h: Add new Stage private API. * clutter/clutter-rectangle.c: Update the get_abs_opacity() call to get_paint_opacity(). * clutter/clutter-stage.c: (clutter_stage_get_preferred_width), (clutter_stage_get_preferred_height), (clutter_stage_allocate), (clutter_stage_class_init): Port Stage to the new size negotiation API. * clutter/clutter-texture.c: Port Texture to the new size negotiation API. * clutter/clutter-types.h: Add ClutterRequestMode enumeration. * clutter/x11/clutter-stage-x11.c: Port the X11 stage implementation to the new size negotiation API. * tests/Makefile.am: Add the layout manager test case. * tests/test-opacity.c: Update. * tests/test-project.c: Update. * tests/test-layout.c: Test case for a layout manager implemented using the new size negotiation API; the layout manager handles both transformed and untransformed children.
2008-06-10 17:07:52 +00:00
clutter_actor_get_transformed_size (priv->fbo_source, &w, &h);
if (w != priv->width || h != priv->height)
{
CoglTextureFlags flags = COGL_TEXTURE_NONE;
gint min_filter, mag_filter;
/* tear down the FBO */
cogl_offscreen_unref (priv->fbo_handle);
texture_free_gl_resources (texture);
priv->width = w;
priv->height = h;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
Fully integrates CoglMaterial throughout the rest of Cogl This glues CoglMaterial in as the fundamental way that Cogl describes how to fill in geometry. It adds cogl_set_source (), which is used to set the material which will be used by all subsequent drawing functions It adds cogl_set_source_texture as a convenience for setting up a default material with a single texture layer, and cogl_set_source_color is now also a convenience for setting up a material with a solid fill. "drawing functions" include, cogl_rectangle, cogl_texture_rectangle, cogl_texture_multiple_rectangles, cogl_texture_polygon (though the cogl_texture_* funcs have been renamed; see below for details), cogl_path_fill/stroke and cogl_vertex_buffer_draw*. cogl_texture_rectangle, cogl_texture_multiple_rectangles and cogl_texture_polygon no longer take a texture handle; instead the current source material is referenced. The functions have also been renamed to: cogl_rectangle_with_texture_coords, cogl_rectangles_with_texture_coords and cogl_polygon respectivly. Most code that previously did: cogl_texture_rectangle (tex_handle, x, y,...); needs to be changed to now do: cogl_set_source_texture (tex_handle); cogl_rectangle_with_texture_coords (x, y,....); In the less likely case where you were blending your source texture with a color like: cogl_set_source_color4ub (r,g,b,a); /* where r,g,b,a isn't just white */ cogl_texture_rectangle (tex_handle, x, y,...); you will need your own material to do that: mat = cogl_material_new (); cogl_material_set_color4ub (r,g,b,a); cogl_material_set_layer (mat, 0, tex_handle)); cogl_set_source_material (mat); Code that uses the texture coordinates, 0, 0, 1, 1 don't need to use cog_rectangle_with_texure_coords since these are the coordinates that cogl_rectangle will use. For cogl_texture_polygon; as well as dropping the texture handle, the n_vertices and vertices arguments were transposed for consistency. So code previously written as: cogl_texture_polygon (tex_handle, 3, verts, TRUE); need to be written as: cogl_set_source_texture (tex_handle); cogl_polygon (verts, 3, TRUE); All of the unit tests have been updated to now use the material API and test-cogl-material has been renamed to test-cogl-multitexture since any textured quad is now technically a test of CoglMaterial but this test specifically creates a material with multiple texture layers. Note: The GLES backend has not been updated yet; that will be done in a following commit.
2009-01-23 16:15:40 +00:00
priv->fbo_texture =
cogl_texture_new_with_size (MAX (priv->width, 1),
MAX (priv->height, 1),
-1,
flags,
COGL_PIXEL_FORMAT_RGBA_8888);
clutter_texture_quality_to_filters (priv->filter_quality,
&min_filter,
&mag_filter);
cogl_texture_set_filters (priv->fbo_texture, min_filter, mag_filter);
priv->fbo_handle = cogl_offscreen_new_to_texture (priv->fbo_texture);
if (priv->fbo_handle == COGL_INVALID_HANDLE)
{
g_warning ("%s: Offscreen texture creation failed", G_STRLOC);
CLUTTER_ACTOR_UNSET_FLAGS (CLUTTER_ACTOR (texture),
CLUTTER_ACTOR_REALIZED);
return;
}
clutter_actor_set_size (CLUTTER_ACTOR (texture), w, h);
}
}
static void
on_fbo_parent_change (ClutterActor *actor,
ClutterActor *old_parent,
ClutterTexture *texture)
{
ClutterActor *parent = CLUTTER_ACTOR(texture);
while ((parent = clutter_actor_get_parent (parent)) != NULL)
if (parent == actor)
{
g_warning ("Offscreen texture is ancestor of source!");
/* Desperate but will avoid infinite loops */
clutter_actor_unparent (actor);
}
}
/**
* clutter_texture_new_from_actor:
* @actor: A source #ClutterActor
*
* Creates a new #ClutterTexture object with its source a prexisting
* actor (and associated children). The textures content will contain
* 'live' redirected output of the actors scene.
*
* Note this function is intented as a utility call for uniformly applying
* shaders to groups and other potential visual effects. It requires that
* the %CLUTTER_FEATURE_OFFSCREEN feature is supported by the current backend
* and the target system.
*
* Some tips on usage:
*
* <itemizedlist>
* <listitem>
* <para>The source actor must be made visible (i.e by calling
* #clutter_actor_show).</para>
* </listitem>
* <listitem>
* <para>The source actor must have a parent in order for it to be
* allocated a size from the layouting mechanism. If the source
* actor does not have a parent when this function is called then
* the ClutterTexture will adopt it and allocate it at its
* preferred size. Using this you can clone an actor that is
* otherwise not displayed. Because of this feature if you do
* intend to display the source actor then you must make sure that
* the actor is parented before calling
* clutter_texture_new_from_actor() or that you unparent it before
* adding it to a container.</para>
* </listitem>
* <listitem>
* <para>When getting the image for the clone texture, Clutter
* will attempt to render the source actor exactly as it would
* appear if it was rendered on screen. The source actor's parent
* transformations are taken into account. Therefore if your
* source actor is rotated along the X or Y axes so that it has
* some depth, the texture will appear differently depending on
* the on-screen location of the source actor. While painting the
* source actor, Clutter will set up a temporary asymmetric
* perspective matrix as the projection matrix so that the source
* actor will be projected as if a small section of the screen was
* being viewed. Before version 0.8.2, an orthogonal identity
* projection was used which meant that the source actor would be
* clipped if any part of it was not on the zero Z-plane.</para>
* </listitem>
* <listitem>
* <para>Avoid reparenting the source with the created texture.</para>
* </listitem>
* <listitem>
* <para>A group can be padded with a transparent rectangle as to
* provide a border to contents for shader output (blurring text
* for example).</para>
* </listitem>
* <listitem>
* <para>The texture will automatically resize to contain a further
* transformed source. However, this involves overhead and can be
* avoided by placing the source actor in a bounding group
* sized large enough to contain any child tranformations.</para>
* </listitem>
* <listitem>
* <para>Uploading pixel data to the texture (e.g by using
* clutter_actor_set_from_file()) will destroy the offscreen texture data
* and end redirection.</para>
* </listitem>
* <listitem>
* <para>cogl_texture_get_data() with the handle returned by
* clutter_texture_get_cogl_texture() can be used to read the
* offscreen texture pixels into a pixbuf.</para>
* </listitem>
* </itemizedlist>
*
* Return value: A newly created #ClutterTexture object, or %NULL on failure.
*
* Since: 0.6
*/
ClutterActor *
clutter_texture_new_from_actor (ClutterActor *actor)
{
ClutterTexture *texture;
ClutterTexturePrivate *priv;
guint w, h;
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
if (clutter_feature_available (CLUTTER_FEATURE_OFFSCREEN) == FALSE)
return NULL;
if (!CLUTTER_ACTOR_IS_REALIZED (actor))
{
clutter_actor_realize (actor);
if (!CLUTTER_ACTOR_IS_REALIZED (actor))
return NULL;
}
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com> Bug #815 - Split up request, allocation, and paint box * clutter/clutter-actor.[ch]: Rework the size allocation, request and paint area. Now ::request_coords() is called ::allocate(), and ::query_coords() has been split into ::get_preferred_width() and ::get_preferred_height(). See the documentation and the layout test on how to implement a container and layout manager with the new API. (#915, based on a patch by Havoc Pennington, Lucas Rocha and Johan Bilien) * clutter/clutter-clone-texture.c: Port CloneTexture to the new size negotiation API; it just means forwarding the requests to the parent texture. * clutter/clutter-deprecated.h: Add deprecated and replaced API. * clutter/clutter-entry.c: Port Entry to the new size negotiation API. * clutter/clutter-group.c: Port Group to the new size negotiation API; the semantics of the Group actor do not change. * clutter/clutter-label.c: Port Label to the new size negotiation API, and vastly simplify the code. * clutter/clutter-main.[ch]: Add API for executing a relayout when needed. * clutter/clutter-private.h: Add new Stage private API. * clutter/clutter-rectangle.c: Update the get_abs_opacity() call to get_paint_opacity(). * clutter/clutter-stage.c: (clutter_stage_get_preferred_width), (clutter_stage_get_preferred_height), (clutter_stage_allocate), (clutter_stage_class_init): Port Stage to the new size negotiation API. * clutter/clutter-texture.c: Port Texture to the new size negotiation API. * clutter/clutter-types.h: Add ClutterRequestMode enumeration. * clutter/x11/clutter-stage-x11.c: Port the X11 stage implementation to the new size negotiation API. * tests/Makefile.am: Add the layout manager test case. * tests/test-opacity.c: Update. * tests/test-project.c: Update. * tests/test-layout.c: Test case for a layout manager implemented using the new size negotiation API; the layout manager handles both transformed and untransformed children.
2008-06-10 17:07:52 +00:00
clutter_actor_get_transformed_size (actor, &w, &h);
if (w == 0 || h == 0)
return NULL;
/* Hopefully now were good.. */
texture = g_object_new (CLUTTER_TYPE_TEXTURE,
"disable-slicing", TRUE,
NULL);
priv = texture->priv;
priv->fbo_source = g_object_ref_sink (actor);
/* If the actor doesn't have a parent then claim it so that it will
get a size allocation during layout */
if (clutter_actor_get_parent (actor) == NULL)
clutter_actor_set_parent (actor, CLUTTER_ACTOR (texture));
/* Connect up any signals which could change our underlying size */
g_signal_connect (actor,
"notify::width",
G_CALLBACK(on_fbo_source_size_change),
texture);
g_signal_connect (actor,
"notify::height",
G_CALLBACK(on_fbo_source_size_change),
texture);
g_signal_connect (actor,
"notify::scale-x",
G_CALLBACK(on_fbo_source_size_change),
texture);
g_signal_connect (actor,
"notify::scale-y",
G_CALLBACK(on_fbo_source_size_change),
texture);
g_signal_connect (actor,
"notify::rotation-angle-x",
G_CALLBACK(on_fbo_source_size_change),
texture);
g_signal_connect (actor,
"notify::rotation-angle-y",
G_CALLBACK(on_fbo_source_size_change),
texture);
g_signal_connect (actor,
"notify::rotation-angle-z",
G_CALLBACK(on_fbo_source_size_change),
texture);
/* And a warning if the source becomes a child of the texture */
g_signal_connect (actor,
"parent-set",
G_CALLBACK(on_fbo_parent_change),
texture);
priv->width = w;
priv->height = h;
clutter_actor_set_size (CLUTTER_ACTOR (texture), priv->width, priv->height);
return CLUTTER_ACTOR (texture);
}
static void
texture_fbo_free_resources (ClutterTexture *texture)
{
ClutterTexturePrivate *priv;
priv = texture->priv;
CLUTTER_MARK();
if (priv->fbo_source != NULL)
{
/* If we parented the texture then unparent it again so that it
will lose the reference */
if (clutter_actor_get_parent (priv->fbo_source)
== CLUTTER_ACTOR (texture))
clutter_actor_unparent (priv->fbo_source);
g_signal_handlers_disconnect_by_func
(priv->fbo_source,
G_CALLBACK(on_fbo_parent_change),
texture);
g_signal_handlers_disconnect_by_func
(priv->fbo_source,
G_CALLBACK(on_fbo_source_size_change),
texture);
g_object_unref (priv->fbo_source);
priv->fbo_source = NULL;
}
if (priv->fbo_handle != COGL_INVALID_HANDLE)
{
cogl_offscreen_unref (priv->fbo_handle);
priv->fbo_handle = COGL_INVALID_HANDLE;
}
}