docs: Add effects chapter, with introduction and first recipe

Add an effects chapter which gives a broad overview of
the abstract classes in the effects API, plus a short
example of how to apply one of the stock Clutter
effects (ClutterColorizeEffect).

The recipe explains how to create a custom ClutterDeformEffect
to produce a page fold (code based on ClutterPageTurnEffect).

The example code includes the effect class plus a small
application to apply it to a texture.
This commit is contained in:
Elliot Smith
2011-02-21 16:43:34 +00:00
parent 91740fd4df
commit 74de3cfdf3
12 changed files with 1255 additions and 0 deletions

View File

@ -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

View File

@ -0,0 +1,250 @@
#include <math.h>
#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;
}

View File

@ -0,0 +1,49 @@
#ifndef __CB_PAGE_FOLD_EFFECT_H__
#define __CB_PAGE_FOLD_EFFECT_H__
#include <clutter/clutter.h>
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__ */

View File

@ -0,0 +1,58 @@
#include <clutter/clutter.h>
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 <path to image file>\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;
}

View File

@ -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 <stdlib.h>
#include <clutter/clutter.h>
#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 <path to image file>\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;
}