diff --git a/doc/cookbook/Makefile.am b/doc/cookbook/Makefile.am index c567cbdeb..5c70e4dfe 100644 --- a/doc/cookbook/Makefile.am +++ b/doc/cookbook/Makefile.am @@ -37,6 +37,8 @@ HTML_FILES = $(top_builddir)/doc/cookbook/html/*.html CSS_FILES = $(top_builddir)/doc/cookbook/html/*.css IMAGE_FILES = \ $(srcdir)/images/clutter-logo.png \ + $(srcdir)/images/effects-basic.png \ + $(srcdir)/images/effects-basic-background.png \ $(srcdir)/images/effects-built-in.png \ $(srcdir)/images/effects-custom-deform.png \ $(srcdir)/images/effects-custom-deform-back-material.png \ diff --git a/doc/cookbook/effects.xml b/doc/cookbook/effects.xml index 2688bc941..d6c02955d 100644 --- a/doc/cookbook/effects.xml +++ b/doc/cookbook/effects.xml @@ -245,6 +245,543 @@ clutter_actor_add_effect (texture, effect); +
+ Changing an actor's paint sequence using + <type>ClutterEffect</type> + +
+ Problem + + You want to paint on top of or under an actor in a generic + way, without editing the actor's paint() + implementation. Example use cases are: + + + + Adding a border on top of an actor. + + + Drawing a background for an actor. + + + + A quick way to achieve the same thing (though not + readily portable between actors) is to connect a callback + before or after an actor's paint signal. + See this recipe for + more details. However, using a ClutterEffect + implementation, as explained in this recipe, is the preferred + approach. +
+ +
+ Solution + + Create a subclass of the ClutterEffect abstract + class; then implement the pre_paint() and/or + post_paint() virtual functions. When the + effect is applied to an actor, these functions will paint + before and after the actor's own paint() + implementation. + + + For this solution, we implement a simple + CbBackgroundEffect which draws a gray rectangle + under an actor. The full source is in + this + section. To keep it simple, the effect has no properties + and isn't configurable (the background is always gray); see the + border + effect for a more detailed implementation with GObject + trimmings. + + + First, create a ClutterEffect subclass. This + requires the trappings of a GObject class; in particular, + it needs a private struct to hold the effect's state. This + should include any CoglMaterials, + CoglColors or other private member variables + you intend to use to draw the effect. + + In the case of the background effect, we have a background + CoglMaterial and a CoglColor for that + material: + + + +struct _CbBackgroundEffectPrivate +{ + CoglMaterial *background; + CoglColor *color; +}; + + + + In the init() function for objects of + your class, create any Cogl resources which you need to draw the + effect. In the case of the background effect, + we need to create the CoglMaterial and + CoglColor for the private struct: + + + +priv = CB_BACKGROUND_EFFECT_GET_PRIVATE (self); + + /* create the background material */ + priv->background = cogl_material_new (); + + /* gray color for filling the background material */ + priv->color = cogl_color_new (); + cogl_color_init_from_4ub (priv->color, 122, 122, 122, 255); + + /* set the color on the material; NB this isn't configurable + * for this effect, and is always gray + */ + cogl_material_set_color (priv->background, priv->color); +} +]]> + + + + Optionally, you can create GObject properties for + the class, if you want a configurable effect: see + this + section for details. + + The dispose() function for your effect + should clean up any Cogl resources: + + + +priv; + + if (priv->background != COGL_INVALID_HANDLE) + { + cogl_handle_unref (priv->background); + priv->background = COGL_INVALID_HANDLE; + } + + if (priv->color != NULL) + { + cogl_color_free (priv->color); + priv->color = NULL; + } + + G_OBJECT_CLASS (cb_background_effect_parent_class)->dispose (gobject); +} +]]> + + + + Now, the important part: implement pre_paint() + and/or post_paint(), using Cogl to draw on the + material(s) set up for the effect. In these functions, you should also + check whether the effect is enabled before drawing. + + For the background effect, we implement pre_paint(), + to draw a gray rectangle under the actor: + + + +priv; + + /* get the associated actor's dimensions */ + actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self)); + clutter_actor_get_size (actor, &width, &height); + + /* draw a Cogl rectangle in the background using the default color */ + cogl_set_source (priv->background); + + /* the rectangle has the same dimensions as the actor */ + cogl_rectangle (0, 0, width, height); + + return TRUE; +} +]]> + + + + Now, in the init() function for the + effect class, assign your implementations to the + virtual methods of the ClutterEffect abstract class: + + + +pre_paint = cb_background_effect_pre_paint; + gobject_class->dispose = cb_background_effect_dispose; + + g_type_class_add_private (klass, sizeof (CbBackgroundEffectPrivate)); +} +]]> + + + + If you intend to make your effect reusable, provide + a public constructor (as is done for the example effects in this + recipe): + + + +ClutterEffect * +cb_background_effect_new () +{ + return g_object_new (CB_TYPE_BACKGROUND_EFFECT, + NULL); +} + + + + The effect is now ready to be used. The application code + for applying your effect to an actor is the same as for any + other effect: + + + +ClutterActor *texture; +ClutterEffect *background_effect; + +/* ...initialize texture, load image file etc... */ + +/* create a gray background effect */ +background_effect = cb_background_effect_new (); + +/* apply the effect to the actor */ +clutter_actor_add_effect (texture, background_effect); + + + + Below is an example of applying this effect to a texture loaded + with an image; the image has a transparent background, so the + background is visible through it. The screenshot is from + the example + application: + + + + + + + + Applying CbBackgroundEffect + to a texture loaded with an image that has a transparent + background + + + + +
+ +
+ Discussion + + A basic ClutterEffect is particularly useful for + amending the appearance of an actor on the fly: for example, + to highlight an actor in response to a button presses. This + could be done by creating a custom widget + whose appearance could be toggled. But what if you wanted to make + an arbitrary actor's appearance "togglable"? A generic effect + in the style of the border effect in this recipe can be applied + to any actor, and easily toggled by enabling/disabling the + effect. + + ClutterEffect works best where + you want to overlay or underlay the actor with Cogl paths or + primitives, without changing the actor's geometry. If you want + to do complicated geometry transformations, or other subtle + manipulations of an actor's appearance, it is better to use + a ClutterEffect subclass like + ClutterOffscreenEffect, ClutterDeformEffect, + or ClutterShaderEffect. + + In a similar vein, when a ClutterEffect is + applied to an actor, the effect shouldn't paint outside the actor's + allocation. However, if the effect provides a + get_paint_volume() implementation which + returns a volume larger than the actor's allocation, the effect + can paint anywhere within that volume. Though + in most cases, creating a custom paint volume is only going to be + useful for offscreen effects, where you are changing the + actor's geometry. + +
+ Effect properties + + If your effect has GObject properties, you should + ensure that an actor associated with the effect is queued + for a redraw when those properties change. (You only need to + do this for properties which change the effect's appearance; + but this is likely to include most of an effect's properties.) + + In most cases, you're likely define standard GObject + properties for the class; for example, + CbBorderEffect + defines a width property like this: + + + + + + + + It also defines a standard GObject + set_property() function for + width: + + + + + + + + Note that this calls + cb_border_effect_set_width(), which is + also exposed in the public API. This is where the + width member variable is actually set in + the private struct; and also where the redraw for the actor + associated with the effect should be queued: + + + +width = width; + + /* the property has been updated, so queue a redraw of the actor (if set) */ + cb_border_effect_update (self); +} +]]> + + + + Any other property setters which affect the associated + actor's appearance (i.e. color in the case of + CbBorderEffect) should also call the update + function after setting the property. + + + If your effect exposes GObject properties in this way, + it can also be animated with the Clutter animation API as usual. + For example, you could animate the border effect in this recipe + so that the border gradually becomes thinner or thicker. + + +
+ +
+ +
+ Full example + + The example application applies two effects to a + group of ClutterTextures: + + + + A CbBackgroundEffect which draws a gray + background under each actor. The effect is implemented in + a header + file and a C + code file. + + + A CbBorderEffect which draws a + red border on top of an actor; this is toggled by clicking + on the actor. The effect is implemented in + a header + file and a C + code file. + + + + The application + creates textures from the file paths specified + on the command line then applies both of these effects to + each texture. In the case of the CbBorderEffect, + a 5 pixel red border is applied; this is also disabled by default, + and enabled when a texture is clicked. + + Here is an example of the output when the application is loaded + with four images: + + + + + + + + Applying CbBackgroundEffect + and a togglable CbBorderEffect + to a several textures + + + + +
+ <type>CbBackgroundEffect</type> + + + <filename>cb-background-effect.h</filename> (header file) + + + a code sample should be here... but isn't + + + + + + <filename>cb-background-effect.c</filename> (code file) + + + a code sample should be here... but isn't + + + +
+ +
+ <type>CbBorderEffect</type> + + This is a more sophisticated effect with configurable + border color and width. + + + <filename>cb-border-effect.h</filename> (header file) + + + a code sample should be here... but isn't + + + + + + <filename>cb-border-effect.c</filename> (code file) + + + a code sample should be here... but isn't + + + +
+ +
+ Application + + + Application which applies <type>CbBorderEffect</type> + and <type>CbBackgroundEffect</type> to a group of + <type>ClutterTextures</type>. + + + a code sample should be here... but isn't + + + +
+ +
+ +
+
Creating and animating a custom <type>ClutterDeformEffect</type> diff --git a/doc/cookbook/images/effects-basic-background.png b/doc/cookbook/images/effects-basic-background.png new file mode 100644 index 000000000..737affe91 Binary files /dev/null and b/doc/cookbook/images/effects-basic-background.png differ diff --git a/doc/cookbook/images/effects-basic.png b/doc/cookbook/images/effects-basic.png new file mode 100644 index 000000000..38c36a258 Binary files /dev/null and b/doc/cookbook/images/effects-basic.png differ