diff --git a/doc/cookbook/Makefile.am b/doc/cookbook/Makefile.am index 6fad1b4db..c567cbdeb 100644 --- a/doc/cookbook/Makefile.am +++ b/doc/cookbook/Makefile.am @@ -16,6 +16,7 @@ XML_FILES = \ $(srcdir)/textures.xml \ $(srcdir)/layouts.xml \ $(srcdir)/script.xml \ + $(srcdir)/effects.xml \ $(NULL) XSLTOPTS = \ @@ -36,6 +37,9 @@ 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-built-in.png \ + $(srcdir)/images/effects-custom-deform.png \ + $(srcdir)/images/effects-custom-deform-back-material.png \ $(srcdir)/images/textures-reflection.png \ $(srcdir)/images/actors-opacity.png \ $(srcdir)/images/actors-opacity-container-affects-opacity.png \ @@ -59,6 +63,7 @@ VIDEO_FILES = \ $(srcdir)/videos/animations-rotating-y-centered.ogv \ $(srcdir)/videos/animations-rotating-z-centered.ogv \ $(srcdir)/videos/animations-rotating-container-reverses-direction.ogv \ + $(srcdir)/videos/effects-custom-deform.ogv \ $(srcdir)/videos/textures-split-go.ogv \ $(srcdir)/videos/events-mouse-scroll.ogv \ $(srcdir)/videos/textures-crossfade-two-textures.ogv \ diff --git a/doc/cookbook/clutter-cookbook.xml.in b/doc/cookbook/clutter-cookbook.xml.in index 83e16476b..96953fa51 100644 --- a/doc/cookbook/clutter-cookbook.xml.in +++ b/doc/cookbook/clutter-cookbook.xml.in @@ -46,6 +46,7 @@ + Contributing to this document diff --git a/doc/cookbook/effects.xml b/doc/cookbook/effects.xml new file mode 100644 index 000000000..2688bc941 --- /dev/null +++ b/doc/cookbook/effects.xml @@ -0,0 +1,769 @@ + + + + Effects + + + Roger Zelazny, from Prince of Chaos + + Don't wake me for the end of the world unless it has very + good special effects + + +
+ Introduction + + Effects modify an actor's appearance, such + as how it is positioned, colored and textured. + + The Clutter API for effects contains several + abstract classes you can subclass to create your own effects. + It also contains several built-in effects you can use to + modify the visual appearance of actors in a variety of ways. + + The recipes in this section of the cookbook cover how to create + your own effects as well as how to apply Clutter's effects. + +
+ Creating effects using the abstract effect classes + + + One of the original design goals of Clutter was to abstract + the complexity of GL. However, the effects API partially circumvents + these abstractions, to give you finer-grained access to the + graphics pipeline. Therefore, if you want to write your own effects, + some understanding of Cogl, OpenGL, and general graphics programming + is essential. + + + Each abstract effect class is tailored to modifying different + aspects of an actor, as explained below: + + + + + + <type>ClutterEffect</type> + If you're just using the Clutter and Cogl APIs to + decorate an actor, this is simplest type of effect to + implement. + + + Subclassing ClutterEffect enables you to + "wrap" how an actor is painted, by injecting some code before + and/or after the actor's own paint() + implementation. + + + This is the preferred way to modify how an actor is + painted, short of creating your own actor subclass. + + + Subclasses of + ClutterEffect: + + + + + + <type>ClutterOffscreenEffect</type> + + Use this class as a basis if you need GL textures + for your effect. + + + GL textures are required for effects which need + an offscreen framebuffer. The offscreen framebuffer is + used to store a modified rendering of an actor (e.g. + with its colors altered or with deformed geometry). + This buffer is then redirected to a texture in the + stage window. + + An example is ClutterBlurEffect, + which uses a GLSL fragment shader to blur an + actor's appearance in an offscreen framebuffer. + + Subclasses of + ClutterOffscreenEffect: + + + + + + + <type>ClutterDeformEffect</type> + + Use this base class if you want to modify + an actor's geometry, at the level of individual + vertices. + + + ClutterDeformEffect removes the + complexity of dealing with vertex-based deformations + at the OpenGL level, instead enabling you to easily plug + a deformation callback into the graphics pipeline. + + If you are writing your own deform effects, + a good example to work from is + ClutterPageTurnEffect. + + There is also a + recipe which + explains how to implement a simple custom deform + effect (a page fold). + + + + + + <type>ClutterShaderEffect</type> + + Use this if you want to apply custom + GLSL vertex or fragment shaders to your actors. + + + Writing ClutterShaderEffects gives + you very fine-grained control over the GL pipeline. + However, this makes them the most complex + effects to implement. + + + If you want to write your own GLSL shaders, the + GLSL + specification is a good starting point. + + + + + + + + + + + + + + +
+ +
+ Using the built-in effects + + Clutter comes with a number of built-in effects + which can easily be applied to your actors. This section + explains how to do this. + + First, create an actor. For this + example, we use a texture loaded with an image: + + + +/* filename could be set from command line or constant */ +gchar *filename; + +/* create a texture */ +ClutterActor *texture = clutter_texture_new (); + +/* ...set texture size, keep aspect ratio etc... */ + +/* NB ignoring missing file errors here for brevity */ +clutter_texture_set_from_file (CLUTTER_TEXTURE (texture), + filename, + NULL); + +/* ...add texture to the stage... */ + + + + Next, create an instance of an effect; here, we're + creating a ClutterColorizeEffect with a pink tint: + + + +ClutterColor *pink = clutter_color_new (230, 187, 210, 255); +ClutterEffect *effect = clutter_colorize_effect_new (pink); + + + + Finally, apply the effect to the actor: + + + +clutter_actor_add_effect (texture, effect); + + + + The result in this case is an image colorized with + a pink tint, like this: + + + + + + + + Applying a ClutterColorizeEffect + to a texture loaded with an image (drawing by + Madeleine Smith) + + + + + The same set of steps applies for any of the built-in + Clutter effects. Your own custom effects classes should also + behave in a similar way: constructors should return + ClutterEffect instances so your effect can + be added to an actor through the standard API. + + One further thing worth mentioning is that because an + effect is a GObject, any properties you expose for your effect + can be animated via implicit animations, + ClutterAnimator or ClutterState. For + example, the ClutterPageTurnEffect can be animated + by manipulating its period property. An example + of how to do this for your own effect is given in the + custom deform effect + recipe. + + The full code for the ClutterColorizeEffect + example is below. + + + Applying a <type>ClutterColorizeEffect</type> to + a texture loaded with an image + + + a code sample should be here... but isn't + + + + +
+ +
+ +
+ Creating and animating a custom <type>ClutterDeformEffect</type> + +
+ Problem + + You want to deform an actor's geometry: for example, + to make it appear stretched, twisted or folded. + + This recipe demonstrates how to do this with a simple page + fold effect, which folds one half of the actor over its other half. +
+ +
+ Solution + + Subclass ClutterDeformEffect and + implement a deform_vertex() function + to modify the actor's vertices. + + The signature for deform_vertex() + is: + + + +void +deform_vertex (ClutterDeformEffect *effect, + gfloat width, + gfloat height, + CoglTextureVertex *vertex); + + + + The width and height + are the width and height of the target material, stored in + the offscreen buffer. Usually the target material's size will + match the actor's transformed size; however, if the effect + implements create_texture(), the target + material's size may differ from the actor's transformed size. + + The vertex contains the position + and color of a vertex, to be deformed by your effect. + Your deform_vertex() + function should modify the member variables of this + CoglTextureVertex in place. Usually, this will + mean modifying the x, y + and y member variables of the vertex, + which describe its position in 3D space. + + The example function below, taken from + the + full example, applies a transformation to vertices falling + in the "right-hand" half of the actor (i.e. vertices with an + x value greater than or equal to half the + width of the actor). + + + +static void +cb_page_fold_effect_deform_vertex (ClutterDeformEffect *effect, + gfloat width, + gfloat height, + CoglTextureVertex *vertex) +{ + CbPageFoldEffectPrivate *priv = CB_PAGE_FOLD_EFFECT (effect)->priv; + + /* the rotation angle is modified by the percentage progress of the fold, + * as represented by the period variable + */ + gfloat radians = (priv->angle * priv->period) / (180.0f / G_PI); + + /* rotate from the center of the actor on the y axis */ + gfloat adjusted_x = vertex->x - (width / 2); + + /* only rotate vertices to the right of the middle of the actor */ + if (adjusted_x >= 0.0) + { + vertex->x = (vertex->z * sin (radians)) + + (adjusted_x * cos (radians)) + + width / 2; + + /* NB add 1 to z to prevent "z fighting"; otherwise, when fully-folded + * the image has "stripes" where vertices from the folded part + * of the actor interfere with vertices from the unfolded part + */ + vertex->z = (vertex->z * cos (radians)) + + (adjusted_x * sin (radians)) + + 1; + } + + /* adjust depth of all vertices so they fit inside the actor while folding; + * this has the effect of making the image smaller within the texture, + * but does produce a cleaner fold animation + */ + vertex->z -= width / 2; +} + + + + Note that this effect has two properties set in its + constructor or through setters: + + + + angle, representing the angle of + the full fold; for the actor to fully fold in half, this + would be set to 180.0 + + + + period, representing the percentage + of the fold to apply + + + + As well as rotating the vertex, the + deform_vertex() function also shifts + the z coordinate "up" by 1 + (towards the viewpoint) for vertices on the right-hand side of the + actor. This is so that the "folded over" vertices + are above vertices on the left-hand side. Without this small + shift, the vertices interfere with each other, which can cause striping + artefacts. + + All vertices are also shifted "down", + so that the the folding part of the actor remains within the texture. + Otherwise the part which is folding may be clipped to the allocation of + the actor. + + This effect can now be applied to an actor, using the + approach + outlined + in the introduction. The result looks like this when + period is set to 0.25 and angle + to 180.0 (i.e. the page is folded by 45 degrees): + + + + + + + + Applying a custom ClutterDeformEffect + to a texture loaded with an image + + + + + Because the effect is a GObject which exposes its + properties, it can easily be animated, as described in + the + discussion section. + +
+ +
+ Discussion + + A deform effect processes an actor as follows: + + + + + The actor is divided into a series of + triangular tiles. The number of + horizontal and vertical tiles is configurable; + more tiles implies more vertices. See + this + section for more details about tiles. + + + + The position of each vertex of each + tile is then modified (or not) by the + deform_vertex() function. In this + function, you can change the vertex's position + (x, y, + z coordinates). You can also + modify the color at the vertex if desired. + + The resulting deformed vertices are stored + in an offscreen buffer. + + + + Once the deformation has been applied to + all vertices, the content of the offscreen buffer + is painted at the onscreen position of the actor. + + + + + You may find it useful to visualise this process by imagining + your actor's surface as a net, composed of triangles. (Something + like a fishing net, not a mathematical one.) At each corner of + each triangle is a marble; and between each pair of corners + is an infinitely flexible length of elastic. Moving a marble + doesn't change the position of its neighbours; it just stretches + or relaxes the elastic. + + In this analogy, the marbles are the vertices; and the + surfaces between the marbles, bordered by triangles of + elastic, are the tiles. More triangles (tiles) means more + marbles (vertices). + + When you create a ClutterDeformEffect, + think of it as specifying movements of marbles in the net. + Changing the position of a vertex corresponds to moving a marble + up/down (-/+ y position), left/right + (-/+ x position) or away/towards + you (-/+ z position) (ignoring color for the + moment). + + Now imagine that you are asked to fold the whole net of + marbles; but you can't just grab the edge of the net and pull + it over: you can only move one marble at a time. However, once moved, + each marble magically stays where you put it in 3D space. + + To do this, you could project where each marble would be if + you could fold the whole sheet in one go; then move the + marbles one by one to their projected positions. Even though + you'd be moving the marbles one at a time, it would eventually + look as though you'd folded the whole net with a single movement. + + When you write a ClutterDeformEffect, you have + to accomplish a similar feat: change the shape of an actor + by individually modifying the positions of points on its surface. In + most cases, your deform_vertex() implementation + can take advantage of an existing geometric transformation + method to achieve this. (For example, the page fold in this recipe + is based on equations from p.412 of Computer + Graphics (C Version), 2nd Edition by Hearn and + Baker, 1996.) + +
+ Customising the back material + + When you set up a deform effect, you + can optionally specify a material to use for the "back" of + any actor it is applied to. + + If you think of an actor as a sheet of paper with a + picture on it, specifying a back is similar to turning the + sheet of paper over (rotating it around the + y axis) and drawing another picture on + the other side. If you then folded or twisted the paper, + you would be able to see parts of the pictures on both the + front and back of the paper. + + Similarly, during deformation of an actor, if any + vertices of the actor are deformed such that the actor's surface + is folded or twisted over itself, parts of its back + become visible. If you set a back material, you will see parts + of that where the surface is folded over. If you don't set a back + material, you will instead see mirror images of parts of the actor's + front: as if the actor was flexible stained glass, rather than paper. + You can see this if you watch the animation in + this + section. + + The back material should be an instance of + CoglMaterial. You can either create this via + the Cogl API directly; or indirectly through the Clutter API + (for example, by getting the material from a + ClutterTexture). The code below gives an example + of how to do the latter: + + + + + + + + See the ClutterDeformEffect API reference + for more details about back materials. + + Here's a screenshot of the + example + with the addition of a back material, folded at an angle + of 60 degrees: + + + + + + + + Applying a custom ClutterDeformEffect + to a texture loaded with an image + + + + +
+ +
+ Animating a custom deform effect + + Clutter's animation API can animate any GObject which + exposes its properties. In the case of the page fold effect, + we can expose the period property using + standard GObject property installation: + + + +/* GObject class init */ +static void +cb_page_fold_effect_class_init (CbPageFoldEffectClass *klass) +{ + GParamSpec *pspec; + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + /* ...other class setup code... */ + + /* expose the period as a GObject property */ + pspec = g_param_spec_double ("period", + "Period", + "The period of the page fold", + 0.0, 1.0, + 0.0, + G_PARAM_READWRITE); + obj_props[PROP_PERIOD] = pspec; + g_object_class_install_property (gobject_class, PROP_PERIOD, pspec); + + /* ...install other properties... */ +} + + + + We also add a get_property() + implementation, as well as a setter (see + the full + GObject implementation for details). + + Then set up an animation for the property; in this case, + using a ClutterState: + + + +ClutterEffect *effect = cb_page_fold_effect_new (180.0, 0.0); + +ClutterState *transitions = clutter_state_new (); +clutter_state_set_duration (transitions, NULL, NULL, 500); + +clutter_state_set (transitions, NULL, "unfolded", + effect, "period", CLUTTER_LINEAR, 0.0, + NULL); + +clutter_state_set (transitions, NULL, "folded", + effect, "period", CLUTTER_LINEAR, 1.0, + NULL); + + + + To start the animation, warp the ClutterState + into its "unfolded" state, then set it to + "folded": + + + +/* this changes state instantaneously */ +clutter_state_warp_to_state (transitions, "unfolded"); + +/* this starts an animation to the state */ +clutter_state_set_state (transitions, "folded"); + + + + Note that the + full code + sample is slightly more complex, as it triggers state + changes when a mouse button is pressed on the texture. There is + also a third "partially folded" state (used to create + the screenshot for the + previous + section). + + Here's what the resulting animation looks like: + + + + + + + Video showing animation of a custom deform effect + on a texture + + + +
+ +
+ Tiles + + A ClutterDeformEffect divides the actor + being deformed into a number of tiles: the larger the number + of tiles, the larger the number of vertices to be manipulated + by the effect. Increasing the number of tiles increases the number of + vertex computations required, which can slow down animations; + at the same time, finer-grained tiles can make an effect appear + smoother, particularly when animated. + + Most of the time, the default number + of tiles in the x and y + axes should suffice. You can get the current number of + tiles associated with an effect with: + + + + + + + + However, if an effect produces jerky or fragmented output, + you want to tweak the number of tiles. Use the + clutter_deform_effect_set_n_tiles() function + to do this: + + + +/* 64 tiles in both axes */ +guint x_tiles = 64; +guint y_tiles = 64; + +clutter_deform_effect_set_n_tiles (CLUTTER_DEFORM_EFFECT (effect), + x_tiles, + y_tiles); + + + +
+ +
+ +
+ Full example + + This example consists of three files: + + + + A header + file for the CbPageFoldEffect GObject. + + + The + code file implementing CbPageFoldEffect. + + + A short + sample application which applies a CbPageFoldEffect + instance to an actor and animates the fold when the actor is + clicked. + + + + As Clutter effect subclasses are written using GObject, + you might find this recipe + (which goes into GObject in more detail) a useful introduction. + + + <filename>cb-page-fold-effect.h</filename> (header file) + + + a code sample should be here... but isn't + + + + + + <filename>cb-page-fold-effect.c</filename> (code file) + + + a code sample should be here... but isn't + + + + + + Application which uses <type>CbPageFoldEffect</type> + to do animated folding of a <type>ClutterTexture</type> + + + a code sample should be here... but isn't + + + + +
+ +
+ +
diff --git a/doc/cookbook/examples/Makefile.am b/doc/cookbook/examples/Makefile.am index 2e4e28acd..fa7a8781a 100644 --- a/doc/cookbook/examples/Makefile.am +++ b/doc/cookbook/examples/Makefile.am @@ -18,6 +18,8 @@ noinst_PROGRAMS = \ animations-rotating \ animations-scaling \ animations-scaling-zoom \ + effects-built-in \ + effects-custom-deform \ text-shadow \ textures-reflection \ textures-split-go \ @@ -81,6 +83,8 @@ animations_reuse_SOURCES = animations-reuse.c animations_rotating_SOURCES = animations-rotating.c animations_scaling_SOURCES = animations-scaling.c animations_scaling_zoom_SOURCES = animations-scaling-zoom.c +effects_built_in_SOURCES = effects-built-in.c +effects_custom_deform_SOURCES = cb-page-fold-effect.c cb-page-fold-effect.h effects-custom-deform.c text_shadow_SOURCES = text-shadow.c textures_reflection_SOURCES = textures-reflection.c textures_split_go_SOURCES = textures-split-go.c diff --git a/doc/cookbook/examples/cb-page-fold-effect.c b/doc/cookbook/examples/cb-page-fold-effect.c new file mode 100644 index 000000000..272703503 --- /dev/null +++ b/doc/cookbook/examples/cb-page-fold-effect.c @@ -0,0 +1,250 @@ +#include +#include "cb-page-fold-effect.h" + +G_DEFINE_TYPE (CbPageFoldEffect, cb_page_fold_effect, CLUTTER_TYPE_DEFORM_EFFECT); + +#define CB_PAGE_FOLD_EFFECT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + CB_TYPE_PAGE_FOLD_EFFECT, \ + CbPageFoldEffectPrivate)) + +struct _CbPageFoldEffectPrivate +{ + gdouble angle; + gdouble period; +}; + +enum { + PROP_0, + + PROP_PERIOD, + PROP_ANGLE, + + PROP_LAST +}; + +static GParamSpec *obj_props[PROP_LAST]; + +/* ClutterDeformEffect implementation */ +static void +cb_page_fold_effect_deform_vertex (ClutterDeformEffect *effect, + gfloat width, + gfloat height, + CoglTextureVertex *vertex) +{ + CbPageFoldEffectPrivate *priv = CB_PAGE_FOLD_EFFECT (effect)->priv; + + gfloat radians = (priv->angle * priv->period) / (180.0f / G_PI); + + /* rotate from the center of the actor on the y axis */ + gfloat adjusted_x = vertex->x - (width / 2); + + /* only rotate vertices to the right of the middle of the actor */ + if (adjusted_x >= 0.0) + { + vertex->x = (vertex->z * sin (radians)) + + (adjusted_x * cos (radians)) + + width / 2; + + /* NB add 1 to z to prevent "z fighting"; otherwise, when fully-folded + * the image has "stripes" where vertices from the folded part + * of the actor interfere with vertices from the unfolded part + */ + vertex->z = (vertex->z * cos (radians)) + + (adjusted_x * sin (radians)) + + 1; + } + + /* adjust depth of all vertices so they fit inside the actor while folding; + * this has the effect of making the image smaller within the texture, + * but does produce a cleaner fold animation + */ + vertex->z -= width / 2; +} + +/* GObject implementation */ +static void +cb_page_fold_effect_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + CbPageFoldEffect *effect = CB_PAGE_FOLD_EFFECT (gobject); + + switch (prop_id) + { + case PROP_PERIOD: + cb_page_fold_effect_set_period (effect, g_value_get_double (value)); + break; + + case PROP_ANGLE: + cb_page_fold_effect_set_angle (effect, g_value_get_double (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +static void +cb_page_fold_effect_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + CbPageFoldEffectPrivate *priv = CB_PAGE_FOLD_EFFECT (gobject)->priv; + + switch (prop_id) + { + case PROP_PERIOD: + g_value_set_double (value, priv->period); + break; + + case PROP_ANGLE: + g_value_set_double (value, priv->angle); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +/* GObject class and instance init */ +static void +cb_page_fold_effect_class_init (CbPageFoldEffectClass *klass) +{ + GParamSpec *pspec; + ClutterDeformEffectClass *effect_class = CLUTTER_DEFORM_EFFECT_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + effect_class->deform_vertex = cb_page_fold_effect_deform_vertex; + + gobject_class->set_property = cb_page_fold_effect_set_property; + gobject_class->get_property = cb_page_fold_effect_get_property; + + g_type_class_add_private (klass, sizeof (CbPageFoldEffectPrivate)); + + /** + * CbPageFoldEffect:period: + * + * The period of the page fold, between 0.0 (no fold) and + * 1.0 (fully folded) + */ + pspec = g_param_spec_double ("period", + "Period", + "The period of the page fold", + 0.0, 1.0, + 0.0, + G_PARAM_READWRITE); + obj_props[PROP_PERIOD] = pspec; + g_object_class_install_property (gobject_class, PROP_PERIOD, pspec); + + /** + * CbPageFoldEffect:angle: + * + * The angle of the page fold, in degrees, between 0.0 and 180.0 + */ + pspec = g_param_spec_double ("angle", + "Angle", + "The angle of the page fold, in degrees", + 0.0, 180.0, + 0.0, + G_PARAM_READWRITE); + obj_props[PROP_ANGLE] = pspec; + g_object_class_install_property (gobject_class, PROP_ANGLE, pspec); +} + +static void +cb_page_fold_effect_init (CbPageFoldEffect *self) +{ + CbPageFoldEffectPrivate *priv; + + priv = self->priv = CB_PAGE_FOLD_EFFECT_GET_PRIVATE (self); + + priv->period = 0.0; + priv->angle = 0.0; +} + +/* public API */ +ClutterEffect * +cb_page_fold_effect_new (gdouble angle, + gdouble period) +{ + return g_object_new (CB_TYPE_PAGE_FOLD_EFFECT, + "angle", angle, + "period", period, + NULL); +} + +/** + * cb_page_fold_effect_set_period: + * @effect: a #CbPageFoldEffect + * @period: the period of the page fold, between 0.0 and 1.0 + * + * Sets the period of the page fold, between 0.0 (no fold) + * and 1.0 (fully folded) + */ +void +cb_page_fold_effect_set_period (CbPageFoldEffect *effect, + gdouble period) +{ + g_return_if_fail (CB_IS_PAGE_FOLD_EFFECT (effect)); + g_return_if_fail (period >= 0.0 && period <= 1.0); + + effect->priv->period = period; + + clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect)); +} + +/** + * cb_page_fold_effect_get_period: + * @effect: a #CbPageFoldEffect + * + * Retrieves the value set using cb_page_fold_effect_get_period() + * + * Return value: the period of the page fold + */ +gdouble +cb_page_fold_effect_get_period (CbPageFoldEffect *effect) +{ + g_return_val_if_fail (CB_IS_PAGE_FOLD_EFFECT (effect), 0.0); + + return effect->priv->period; +} + +/** + * cb_page_fold_effect_set_angle: + * @effect: #CbPageFoldEffect + * @angle: the angle of the page fold, in degrees + * + * Sets the angle of the page fold, in degrees; must be a value between + * 0.0 and 180.0 + */ +void +cb_page_fold_effect_set_angle (CbPageFoldEffect *effect, + gdouble angle) +{ + g_return_if_fail (CB_IS_PAGE_FOLD_EFFECT (effect)); + g_return_if_fail (angle >= 0.0 && angle <= 180.0); + + effect->priv->angle = angle; + + clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect)); +} + +/** + * cb_page_fold_effect_get_angle: + * @effect: a #CbPageFoldEffect: + * + * Retrieves the angle of the page fold, in degrees + * + * Return value: the angle of the page fold + */ +gdouble +cb_page_fold_effect_get_angle (CbPageFoldEffect *effect) +{ + g_return_val_if_fail (CB_IS_PAGE_FOLD_EFFECT (effect), 0.0); + + return effect->priv->angle; +} diff --git a/doc/cookbook/examples/cb-page-fold-effect.h b/doc/cookbook/examples/cb-page-fold-effect.h new file mode 100644 index 000000000..1fcb8d746 --- /dev/null +++ b/doc/cookbook/examples/cb-page-fold-effect.h @@ -0,0 +1,49 @@ +#ifndef __CB_PAGE_FOLD_EFFECT_H__ +#define __CB_PAGE_FOLD_EFFECT_H__ + +#include + +GType cb_page_fold_effect_get_type (void); + +#define CB_TYPE_PAGE_FOLD_EFFECT (cb_page_fold_effect_get_type ()) +#define CB_PAGE_FOLD_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + CB_TYPE_PAGE_FOLD_EFFECT, \ + CbPageFoldEffect)) +#define CB_IS_PAGE_FOLD_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + CB_TYPE_PAGE_FOLD_EFFECT)) +#define CB_PAGE_FOLD_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \ + CB_TYPE_PAGE_FOLD_EFFECT, \ + CbPageFoldEffectClass)) +#define CB_IS_PAGE_FOLD_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + CB_TYPE_PAGE_FOLD_EFFECT)) +#define CB_PAGE_FOLD_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + CB_TYPE_PAGE_FOLD_EFFECT, \ + CbPageFoldEffectClass)) + +typedef struct _CbPageFoldEffectPrivate CbPageFoldEffectPrivate; +typedef struct _CbPageFoldEffect CbPageFoldEffect; +typedef struct _CbPageFoldEffectClass CbPageFoldEffectClass; + +/* object */ +struct _CbPageFoldEffect +{ + ClutterDeformEffect parent_instance; + CbPageFoldEffectPrivate *priv; +}; + +/* class */ +struct _CbPageFoldEffectClass +{ + ClutterDeformEffectClass parent_class; +}; + +ClutterEffect *cb_page_fold_effect_new (gdouble angle, + gdouble period); +void cb_page_fold_effect_set_angle (CbPageFoldEffect *effect, + gdouble angle); +void cb_page_fold_effect_set_period (CbPageFoldEffect *effect, + gdouble period); +gdouble cb_page_fold_effect_get_period (CbPageFoldEffect *effect); +gdouble cb_page_fold_effect_get_angle (CbPageFoldEffect *effect); + +#endif /* __CB_PAGE_FOLD_EFFECT_H__ */ diff --git a/doc/cookbook/examples/effects-built-in.c b/doc/cookbook/examples/effects-built-in.c new file mode 100644 index 000000000..a7eb3ceef --- /dev/null +++ b/doc/cookbook/examples/effects-built-in.c @@ -0,0 +1,58 @@ +#include + +int +main (int argc, + char *argv[]) +{ + ClutterActor *stage; + ClutterActor *texture; + ClutterConstraint *constraint_x; + ClutterConstraint *constraint_y; + ClutterColor *pink; + ClutterEffect *effect; + gchar *filename; + + if (argc < 2) + { + g_print ("Usage: %s \n", argv[0]); + return 1; + } + + filename = argv[1]; + + clutter_init (&argc, &argv); + + stage = clutter_stage_new (); + clutter_actor_set_size (stage, 400, 400); + g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); + + texture = clutter_texture_new (); + clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (texture), TRUE); + clutter_actor_set_width (texture, 300); + + /* NB ignoring missing file errors here for brevity */ + clutter_texture_set_from_file (CLUTTER_TEXTURE (texture), + filename, + NULL); + + /* align the texture on the x and y axes */ + constraint_x = clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5); + constraint_y = clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5); + clutter_actor_add_constraint (texture, constraint_x); + clutter_actor_add_constraint (texture, constraint_y); + + /* create a colorize effect with pink tint */ + pink = clutter_color_new (230, 187, 210, 255); + effect = clutter_colorize_effect_new (pink); + + /* apply the effect to the texture */ + clutter_actor_add_effect (texture, effect); + + clutter_container_add_actor (CLUTTER_CONTAINER (stage), texture); + + clutter_actor_show (stage); + + clutter_main (); + + return 0; +} diff --git a/doc/cookbook/examples/effects-custom-deform.c b/doc/cookbook/examples/effects-custom-deform.c new file mode 100644 index 000000000..55094bfd4 --- /dev/null +++ b/doc/cookbook/examples/effects-custom-deform.c @@ -0,0 +1,119 @@ +/* Example of using a custom CbPageFoldEffect to do + * an animated fold of a texture containing an image + * + * Pass the full path to the image on the command line; + * click on the texture to trigger the folding animation + */ +#include +#include + +#include "cb-page-fold-effect.h" + +static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff }; + +static gboolean +button_pressed_cb (ClutterActor *actor, + ClutterEvent *event, + gpointer user_data) +{ + ClutterState *transitions = CLUTTER_STATE (user_data); + + if (g_strcmp0 (clutter_state_get_state (transitions), "folded") == 0) + clutter_state_set_state (transitions, "unfolded"); + else + clutter_state_set_state (transitions, "folded"); + + return TRUE; +} + +int +main (int argc, + char *argv[]) +{ + ClutterActor *stage; + ClutterActor *texture; + ClutterEffect *effect; + ClutterState *transitions; + GError *error = NULL; + + gchar *filename; + + if (argc < 2) + { + g_print ("Usage: %s \n", argv[0]); + return EXIT_FAILURE; + } + + filename = argv[1]; + + clutter_init (&argc, &argv); + + stage = clutter_stage_new (); + clutter_actor_set_size (stage, 400, 300); + clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); + g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); + + texture = clutter_texture_new (); + clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (texture), TRUE); + clutter_actor_set_width (texture, 400); + clutter_actor_set_reactive (texture, TRUE); + clutter_texture_set_from_file (CLUTTER_TEXTURE (texture), + filename, + &error); + + if (error != NULL) + { + g_critical ("Error loading texture from file %s; error was:\n%s", + filename, + error->message); + return EXIT_FAILURE; + } + + /* create the page fold effect instance with destination fold angle + * of 180 degrees and starting period of 0 (no folding) + */ + effect = cb_page_fold_effect_new (180.0, 0.0); + + /* add the effect to the texture actor */ + clutter_actor_add_effect (texture, effect); + + clutter_container_add_actor (CLUTTER_CONTAINER (stage), texture); + + /* animation for the period property of the effect, + * to animate its value between 0.0 and 1.0 and back + */ + transitions = clutter_state_new (); + clutter_state_set_duration (transitions, NULL, NULL, 500); + + clutter_state_set_duration (transitions, + "partially-folded", + "folded", + 375); + + clutter_state_set (transitions, NULL, "folded", + effect, "period", CLUTTER_LINEAR, 1.0, + NULL); + + clutter_state_set (transitions, NULL, "partially-folded", + effect, "period", CLUTTER_LINEAR, 0.25, + NULL); + + clutter_state_set (transitions, NULL, "unfolded", + effect, "period", CLUTTER_LINEAR, 0.0, + NULL); + + clutter_state_warp_to_state (transitions, "partially-folded"); + + g_signal_connect (texture, + "button-press-event", + G_CALLBACK (button_pressed_cb), + transitions); + + clutter_actor_show (stage); + + clutter_main (); + + g_object_unref (transitions); + + return EXIT_SUCCESS; +} diff --git a/doc/cookbook/images/effects-built-in.png b/doc/cookbook/images/effects-built-in.png new file mode 100644 index 000000000..81606023d Binary files /dev/null and b/doc/cookbook/images/effects-built-in.png differ diff --git a/doc/cookbook/images/effects-custom-deform-back-material.png b/doc/cookbook/images/effects-custom-deform-back-material.png new file mode 100644 index 000000000..975e227eb Binary files /dev/null and b/doc/cookbook/images/effects-custom-deform-back-material.png differ diff --git a/doc/cookbook/images/effects-custom-deform.png b/doc/cookbook/images/effects-custom-deform.png new file mode 100644 index 000000000..83dc9dff3 Binary files /dev/null and b/doc/cookbook/images/effects-custom-deform.png differ diff --git a/doc/cookbook/videos/effects-custom-deform.ogv b/doc/cookbook/videos/effects-custom-deform.ogv new file mode 100644 index 000000000..bf7f95978 Binary files /dev/null and b/doc/cookbook/videos/effects-custom-deform.ogv differ