diff --git a/clutter/Makefile.am b/clutter/Makefile.am
index 560780363..6a7f789f1 100644
--- a/clutter/Makefile.am
+++ b/clutter/Makefile.am
@@ -95,6 +95,7 @@ source_h = \
$(srcdir)/clutter-colorize-effect.h \
$(srcdir)/clutter-constraint.h \
$(srcdir)/clutter-container.h \
+ $(srcdir)/clutter-deform-effect.h \
$(srcdir)/clutter-deprecated.h \
$(srcdir)/clutter-desaturate-effect.h \
$(srcdir)/clutter-device-manager.h \
@@ -117,6 +118,7 @@ source_h = \
$(srcdir)/clutter-media.h \
$(srcdir)/clutter-model.h \
$(srcdir)/clutter-offscreen-effect.h \
+ $(srcdir)/clutter-page-turn-effect.h \
$(srcdir)/clutter-path.h \
$(srcdir)/clutter-rectangle.h \
$(srcdir)/clutter-score.h \
@@ -182,6 +184,7 @@ source_c = \
$(srcdir)/clutter-colorize-effect.c \
$(srcdir)/clutter-constraint.c \
$(srcdir)/clutter-container.c \
+ $(srcdir)/clutter-deform-effect.c \
$(srcdir)/clutter-desaturate-effect.c \
$(srcdir)/clutter-device-manager.c \
$(srcdir)/clutter-drag-action.c \
@@ -205,6 +208,7 @@ source_c = \
$(srcdir)/clutter-media.c \
$(srcdir)/clutter-model.c \
$(srcdir)/clutter-offscreen-effect.c \
+ $(srcdir)/clutter-page-turn-effect.c \
$(srcdir)/clutter-path.c \
$(srcdir)/clutter-rectangle.c \
$(srcdir)/clutter-score.c \
diff --git a/clutter/clutter-deform-effect.c b/clutter/clutter-deform-effect.c
new file mode 100644
index 000000000..ff96816f1
--- /dev/null
+++ b/clutter/clutter-deform-effect.c
@@ -0,0 +1,739 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * 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, see .
+ *
+ * Author:
+ * Emmanuele Bassi
+ *
+ * Based on the MxDeformTexture class, written by:
+ * Chris Lord
+ */
+
+/**
+ * SECTION:clutter-deform-effect
+ * @Title: ClutterDeformEffect
+ * @Short_Description: A base class for effects deforming the geometry
+ * of an actor
+ *
+ * #ClutterDeformEffect is an abstract class providing all the plumbing
+ * for creating effects that result in the deformation of an actor's
+ * geometry.
+ *
+ * #ClutterDeformEffect uses offscreen buffers to render the contents of
+ * a #ClutterActor and then the Cogl vertex buffers API to submit the
+ * geomtry to the GPU.
+ *
+ *
+ * Implementing ClutterDeformEffect
+ * Sub-classes of #ClutterDeformEffect should override the
+ * deform_vertex() virtual function; this function
+ * is called on every vertex that needs to be deformed by the effect.
+ * Each passed vertex is an in-out parameter that initially contains the
+ * position of the vertex and should be modified according to a specific
+ * deformation algorithm.
+ *
+ *
+ * #ClutterDeformEffect is available since Clutter 1.4
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter-deform-effect.h"
+
+#include
+
+#include "clutter-debug.h"
+#include "clutter-enum-types.h"
+#include "clutter-private.h"
+
+#define DEFAULT_N_TILES 32
+
+struct _ClutterDeformEffectPrivate
+{
+ CoglHandle back_material;
+
+ gint x_tiles;
+ gint y_tiles;
+
+ CoglHandle vbo;
+
+ CoglHandle indices;
+ CoglHandle back_indices;
+ gint n_indices;
+
+ CoglTextureVertex *vertices;
+
+ gulong allocation_id;
+
+ guint is_dirty : 1;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_X_TILES,
+ PROP_Y_TILES,
+
+ PROP_BACK_MATERIAL
+};
+
+G_DEFINE_ABSTRACT_TYPE (ClutterDeformEffect,
+ clutter_deform_effect,
+ CLUTTER_TYPE_OFFSCREEN_EFFECT);
+
+static void
+clutter_deform_effect_real_deform_vertex (ClutterDeformEffect *effect,
+ gfloat width,
+ gfloat height,
+ CoglTextureVertex *vertex)
+{
+ g_warning ("%s: Deformation effect of type '%s' does not implement "
+ "the required ClutterDeformEffect::deform_vertex virtual "
+ "function.",
+ G_STRLOC,
+ G_OBJECT_TYPE_NAME (effect));
+}
+
+void
+_clutter_deform_effect_deform_vertex (ClutterDeformEffect *effect,
+ gfloat width,
+ gfloat height,
+ CoglTextureVertex *vertex)
+{
+ CLUTTER_DEFORM_EFFECT_GET_CLASS (effect)->deform_vertex (effect,
+ width, height,
+ vertex);
+}
+
+static void
+vbo_invalidate (ClutterActor *actor,
+ const ClutterActorBox *allocation,
+ ClutterAllocationFlags flags,
+ ClutterDeformEffect *effect)
+{
+ effect->priv->is_dirty = TRUE;
+}
+
+static void
+clutter_deform_effect_set_actor (ClutterActorMeta *meta,
+ ClutterActor *actor)
+{
+ ClutterDeformEffectPrivate *priv = CLUTTER_DEFORM_EFFECT (meta)->priv;
+
+ if (priv->allocation_id != 0)
+ {
+ ClutterActor *old_actor = clutter_actor_meta_get_actor (meta);
+
+ g_signal_handler_disconnect (old_actor, priv->allocation_id);
+ priv->allocation_id = 0;
+ }
+
+ /* we need to invalidate the VBO whenever the allocation of the actor
+ * changes
+ */
+ if (actor != NULL)
+ priv->allocation_id = g_signal_connect (actor, "allocation-changed",
+ G_CALLBACK (vbo_invalidate),
+ meta);
+
+ priv->is_dirty = TRUE;
+
+ CLUTTER_ACTOR_META_CLASS (clutter_deform_effect_parent_class)->set_actor (meta, actor);
+}
+
+static void
+clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect)
+{
+ ClutterDeformEffect *self= CLUTTER_DEFORM_EFFECT (effect);
+ ClutterDeformEffectPrivate *priv = self->priv;
+ gboolean is_depth_enabled, is_cull_enabled;
+ CoglHandle material;
+ gint n_tiles;
+
+ if (priv->is_dirty)
+ {
+ ClutterActor *actor;
+ gfloat width, height;
+ guint opacity;
+ gint i, j;
+
+ actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
+ opacity = clutter_actor_get_paint_opacity (actor);
+ clutter_actor_get_size (actor, &width, &height);
+
+ for (i = 0; i < priv->y_tiles + 1; i++)
+ {
+ for (j = 0; j < priv->x_tiles + 1; j++)
+ {
+ CoglTextureVertex *vertex;
+
+ vertex = &priv->vertices[(i * (priv->x_tiles + 1)) + j];
+
+ vertex->tx = (float) j / priv->x_tiles;
+ vertex->ty = (float) i / priv->y_tiles;
+
+ vertex->x = width * vertex->tx;
+ vertex->y = height * vertex->ty;
+ vertex->z = 0.0f;
+
+ cogl_color_set_from_4ub (&vertex->color, 255, 255, 255, opacity);
+
+ _clutter_deform_effect_deform_vertex (self, width, height, vertex);
+ }
+ }
+
+ /* XXX in theory, the sub-classes should tell us what they changed
+ * in the texture vertices; we then would be able to avoid resubmitting
+ * the same data, if it did not change. for the time being, we resubmit
+ * everything
+ */
+ cogl_vertex_buffer_add (priv->vbo, "gl_Vertex",
+ 3,
+ COGL_ATTRIBUTE_TYPE_FLOAT,
+ FALSE,
+ sizeof (CoglTextureVertex),
+ &priv->vertices->x);
+ cogl_vertex_buffer_add (priv->vbo, "gl_MultiTexCoord0",
+ 2,
+ COGL_ATTRIBUTE_TYPE_FLOAT,
+ FALSE,
+ sizeof (CoglTextureVertex),
+ &priv->vertices->tx);
+ cogl_vertex_buffer_add (priv->vbo, "gl_Color",
+ 4,
+ COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE,
+ FALSE,
+ sizeof (CoglTextureVertex),
+ &priv->vertices->color);
+
+ priv->is_dirty = FALSE;
+ }
+
+ /* enable depth test, if it's not already enabled */
+ is_depth_enabled = cogl_get_depth_test_enabled ();
+ if (!is_depth_enabled)
+ cogl_set_depth_test_enabled (TRUE);
+
+ /* enable backface culling if it's not already enabled and if
+ * we have a back material
+ */
+ is_cull_enabled = cogl_get_backface_culling_enabled ();
+ if (priv->back_material != COGL_INVALID_HANDLE && !is_cull_enabled)
+ cogl_set_backface_culling_enabled (TRUE);
+ else if (priv->back_material == COGL_INVALID_HANDLE && is_cull_enabled)
+ cogl_set_backface_culling_enabled (FALSE);
+
+ n_tiles = (priv->x_tiles + 1) * (priv->y_tiles + 1);
+
+ /* draw the front */
+ material = clutter_offscreen_effect_get_target (effect);
+ if (material != COGL_INVALID_HANDLE)
+ {
+ cogl_set_source (material);
+ cogl_vertex_buffer_draw_elements (priv->vbo,
+ COGL_VERTICES_MODE_TRIANGLE_STRIP,
+ priv->indices,
+ 0,
+ n_tiles,
+ 0,
+ priv->n_indices);
+ }
+
+ /* draw the back */
+ material = priv->back_material;
+ if (material != COGL_INVALID_HANDLE)
+ {
+ cogl_set_source (priv->back_material);
+ cogl_vertex_buffer_draw_elements (priv->vbo,
+ COGL_VERTICES_MODE_TRIANGLE_STRIP,
+ priv->back_indices,
+ 0,
+ n_tiles,
+ 0,
+ priv->n_indices);
+ }
+
+ /* restore the previous state */
+ if (!is_depth_enabled)
+ cogl_set_depth_test_enabled (FALSE);
+
+ if (priv->back_material != COGL_INVALID_HANDLE && !is_cull_enabled)
+ cogl_set_backface_culling_enabled (FALSE);
+ else if (priv->back_material == COGL_INVALID_HANDLE && is_cull_enabled)
+ cogl_set_backface_culling_enabled (TRUE);
+}
+
+static inline void
+clutter_deform_effect_free_arrays (ClutterDeformEffect *self)
+{
+ ClutterDeformEffectPrivate *priv = self->priv;
+
+ if (priv->vbo != COGL_INVALID_HANDLE)
+ {
+ cogl_handle_unref (priv->vbo);
+ priv->vbo = COGL_INVALID_HANDLE;
+ }
+
+ if (priv->indices != COGL_INVALID_HANDLE)
+ {
+ cogl_handle_unref (priv->indices);
+ priv->indices = COGL_INVALID_HANDLE;
+ }
+
+ g_free (priv->vertices);
+ priv->vertices = NULL;
+}
+
+static void
+clutter_deform_effect_init_arrays (ClutterDeformEffect *self)
+{
+ ClutterDeformEffectPrivate *priv = self->priv;
+ GLushort *static_indices, *static_back_indices;
+ GLushort *idx, *back_idx;
+ gint x, y, direction;
+ gint n_tiles;
+
+ clutter_deform_effect_free_arrays (self);
+
+ priv->n_indices = (2 + 2 * priv->x_tiles)
+ * priv->y_tiles
+ + (priv->y_tiles - 1);
+
+ static_indices = g_new (GLushort, priv->n_indices);
+ static_back_indices = g_new (GLushort, priv->n_indices);
+
+#define MESH_INDEX(x,y) ((y) * (priv->x_tiles + 1) + (x))
+
+ /* compute all the triangles from the various tiles */
+ direction = 1;
+
+ idx = static_indices;
+ idx[0] = MESH_INDEX (0, 0);
+ idx[1] = MESH_INDEX (0, 1);
+ idx += 2;
+
+ back_idx = static_back_indices;
+ back_idx[0] = MESH_INDEX (priv->x_tiles, 0);
+ back_idx[1] = MESH_INDEX (priv->x_tiles, 1);
+ back_idx += 2;
+
+ for (y = 0; y < priv->y_tiles; y++)
+ {
+ for (x = 0; x < priv->x_tiles; x++)
+ {
+ if (direction)
+ {
+ idx[0] = MESH_INDEX (x + 1, y);
+ idx[1] = MESH_INDEX (x + 1, y + 1);
+
+ back_idx[0] = MESH_INDEX (priv->x_tiles - (x + 1), y);
+ back_idx[1] = MESH_INDEX (priv->x_tiles - (x + 1), y + 1);
+ }
+ else
+ {
+ idx[0] = MESH_INDEX (priv->x_tiles - x - 1, y);
+ idx[1] = MESH_INDEX (priv->x_tiles - x - 1, y + 1);
+
+ back_idx[0] = MESH_INDEX (x + 1, y);
+ back_idx[1] = MESH_INDEX (x + 1, y + 1);
+ }
+
+ idx += 2;
+ back_idx += 2;
+ }
+
+ if (y == (priv->y_tiles - 1))
+ break;
+
+ if (direction)
+ {
+ idx[0] = MESH_INDEX (priv->x_tiles, y + 1);
+ idx[1] = MESH_INDEX (priv->x_tiles, y + 1);
+ idx[2] = MESH_INDEX (priv->x_tiles, y + 2);
+
+ back_idx[0] = MESH_INDEX (0, y + 1);
+ back_idx[1] = MESH_INDEX (0, y + 1);
+ back_idx[2] = MESH_INDEX (0, y + 2);
+ }
+ else
+ {
+ idx[0] = MESH_INDEX (0, y + 1);
+ idx[1] = MESH_INDEX (0, y + 1);
+ idx[2] = MESH_INDEX (0, y + 2);
+
+ back_idx[0] = MESH_INDEX (priv->x_tiles, y + 1);
+ back_idx[1] = MESH_INDEX (priv->x_tiles, y + 1);
+ back_idx[2] = MESH_INDEX (priv->x_tiles, y + 2);
+ }
+
+ idx += 3;
+ back_idx += 3;
+
+ direction = !direction;
+ }
+
+#undef MESH_INDEX
+
+ priv->indices =
+ cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT,
+ static_indices,
+ priv->n_indices);
+ priv->back_indices =
+ cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT,
+ static_back_indices,
+ priv->n_indices);
+
+ g_free (static_indices);
+ g_free (static_back_indices);
+
+ n_tiles = (priv->x_tiles + 1) * (priv->y_tiles + 1);
+ priv->vertices = g_new (CoglTextureVertex, n_tiles);
+ priv->vbo = cogl_vertex_buffer_new (n_tiles);
+
+ priv->is_dirty = TRUE;
+}
+
+static inline void
+clutter_deform_effect_free_back_material (ClutterDeformEffect *self)
+{
+ ClutterDeformEffectPrivate *priv = self->priv;
+
+ if (priv->back_material != NULL)
+ {
+ cogl_handle_unref (priv->back_material);
+ priv->back_material = COGL_INVALID_HANDLE;
+ }
+}
+
+static void
+clutter_deform_effect_finalize (GObject *gobject)
+{
+ ClutterDeformEffect *self = CLUTTER_DEFORM_EFFECT (gobject);
+
+ clutter_deform_effect_free_arrays (self);
+ clutter_deform_effect_free_back_material (self);
+
+ G_OBJECT_CLASS (clutter_deform_effect_parent_class)->finalize (gobject);
+}
+
+static void
+clutter_deform_effect_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterDeformEffect *self = CLUTTER_DEFORM_EFFECT (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_X_TILES:
+ clutter_deform_effect_set_n_tiles (self, g_value_get_uint (value),
+ self->priv->y_tiles);
+ break;
+
+ case PROP_Y_TILES:
+ clutter_deform_effect_set_n_tiles (self, self->priv->x_tiles,
+ g_value_get_uint (value));
+ break;
+
+ case PROP_BACK_MATERIAL:
+ clutter_deform_effect_set_back_material (self, g_value_get_boxed (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+clutter_deform_effect_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterDeformEffectPrivate *priv = CLUTTER_DEFORM_EFFECT (gobject)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_X_TILES:
+ g_value_set_uint (value, priv->x_tiles);
+ break;
+
+ case PROP_Y_TILES:
+ g_value_set_uint (value, priv->y_tiles);
+ break;
+
+ case PROP_BACK_MATERIAL:
+ g_value_set_boxed (value, priv->back_material);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+clutter_deform_effect_class_init (ClutterDeformEffectClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
+ ClutterOffscreenEffectClass *offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (ClutterDeformEffectPrivate));
+
+ klass->deform_vertex = clutter_deform_effect_real_deform_vertex;
+
+ gobject_class->set_property = clutter_deform_effect_set_property;
+ gobject_class->get_property = clutter_deform_effect_get_property;
+ gobject_class->finalize = clutter_deform_effect_finalize;
+
+ /**
+ * ClutterDeformEffect:x-tiles:
+ *
+ * The number of horizontal tiles. The bigger the number, the
+ * smaller the tiles
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_uint ("x-tiles",
+ "Horiontal Tiles",
+ "The number of horizontal tiles",
+ 1, G_MAXUINT,
+ DEFAULT_N_TILES,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_X_TILES, pspec);
+
+ /**
+ * ClutterDeformEffect:y-tiles:
+ *
+ * The number of vertical tiles. The bigger the number, the
+ * smaller the tiles
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_uint ("y-tiles",
+ "Vertical Tiles",
+ "The number of vertical tiles",
+ 1, G_MAXUINT,
+ DEFAULT_N_TILES,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_Y_TILES, pspec);
+
+ /**
+ * ClutterDeformEffect:back-material:
+ *
+ * A material to be used when painting the back of the actor
+ * to which this effect has been applied
+ *
+ * By default, no material will be used
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_boxed ("back-material",
+ "Back Material",
+ "The material to be used when painting the "
+ "back of the actor",
+ COGL_TYPE_HANDLE,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_BACK_MATERIAL, pspec);
+
+ meta_class->set_actor = clutter_deform_effect_set_actor;
+
+ offscreen_class->paint_target = clutter_deform_effect_paint_target;
+}
+
+static void
+clutter_deform_effect_init (ClutterDeformEffect *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_DEFORM_EFFECT,
+ ClutterDeformEffectPrivate);
+
+ self->priv->x_tiles = self->priv->y_tiles = DEFAULT_N_TILES;
+ self->priv->back_material = COGL_INVALID_HANDLE;
+
+ clutter_deform_effect_init_arrays (self);
+}
+
+/**
+ * clutter_deform_effect_set_back_material:
+ * @effect: a #ClutterDeformEffect
+ * @material: (allow-none): a handle to a Cogl material
+ *
+ * Sets the material that should be used when drawing the back face
+ * of the actor during a deformation
+ *
+ * The #ClutterDeformEffect will take a reference on the material's
+ * handle
+ *
+ * Since: 1.4
+ */
+void
+clutter_deform_effect_set_back_material (ClutterDeformEffect *effect,
+ CoglHandle material)
+{
+ ClutterDeformEffectPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect));
+ g_return_if_fail (material == COGL_INVALID_HANDLE || cogl_is_material (material));
+
+ priv = effect->priv;
+
+ clutter_deform_effect_free_back_material (effect);
+
+ priv->back_material = material;
+ if (priv->back_material != COGL_INVALID_HANDLE)
+ cogl_handle_ref (priv->back_material);
+
+ clutter_deform_effect_invalidate (effect);
+}
+
+/**
+ * clutter_deform_effect_get_back_material:
+ * @effect: a #ClutterDeformEffect
+ *
+ * Retrieves the handle to the back face material used by @effect
+ *
+ * Return value: (transfer none): a handle for the material, or %NULL.
+ * The returned material is owned by the #ClutterDeformEffect and it
+ * should not be freed directly
+ *
+ * Since: 1.4
+ */
+CoglHandle
+clutter_deform_effect_get_back_material (ClutterDeformEffect *effect)
+{
+ g_return_val_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect), NULL);
+
+ return effect->priv->back_material;
+}
+
+/**
+ * clutter_deform_effect_set_n_tiles:
+ * @effect: a #ClutterDeformEffect
+ * @x_tiles: number of horizontal tiles
+ * @y_tiles: number of vertical tiles
+ *
+ * Sets the number of horizontal and vertical tiles to be used
+ * when applying the effect
+ *
+ * More tiles allow a finer grained deformation at the expenses
+ * of computation
+ *
+ * Since: 1.4
+ */
+void
+clutter_deform_effect_set_n_tiles (ClutterDeformEffect *effect,
+ guint x_tiles,
+ guint y_tiles)
+{
+ ClutterDeformEffectPrivate *priv;
+ gboolean tiles_changed = FALSE;
+
+ g_return_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect));
+ g_return_if_fail (x_tiles > 0 && y_tiles > 0);
+
+ priv = effect->priv;
+
+ g_object_freeze_notify (G_OBJECT (effect));
+
+ if (priv->x_tiles != x_tiles)
+ {
+ priv->x_tiles = x_tiles;
+
+ g_object_notify (G_OBJECT (effect), "x-tiles");
+
+ tiles_changed = TRUE;
+ }
+
+ if (priv->y_tiles != y_tiles)
+ {
+ priv->y_tiles = y_tiles;
+
+ g_object_notify (G_OBJECT (effect), "y-tiles");
+
+ tiles_changed = TRUE;
+ }
+
+ if (tiles_changed)
+ {
+ clutter_deform_effect_init_arrays (effect);
+ clutter_deform_effect_invalidate (effect);
+ }
+
+ g_object_thaw_notify (G_OBJECT (effect));
+}
+
+/**
+ * clutter_deform_effect_get_n_tiles:
+ * @effect: a #ClutterDeformEffect
+ * @x_tiles: (out): return location for the number of horizontal tiles,
+ * or %NULL
+ * @y_tiles: (out): return location for the number of vertical tiles,
+ * or %NULL
+ *
+ * Retrieves the number of horizontal and vertical tiles used to sub-divide
+ * the actor's geometry during the effect
+ *
+ * Since: 1.4
+ */
+void
+clutter_deform_effect_get_n_tiles (ClutterDeformEffect *effect,
+ guint *x_tiles,
+ guint *y_tiles)
+{
+ g_return_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect));
+
+ if (x_tiles != NULL)
+ *x_tiles = effect->priv->x_tiles;
+
+ if (y_tiles != NULL)
+ *y_tiles = effect->priv->y_tiles;
+}
+
+/**
+ * clutter_deform_effect_invalidate:
+ * @effect: a #ClutterDeformEffect
+ *
+ * Invalidates the @effect's vertices and, if it is associated
+ * to an actor, it will queue a redraw
+ *
+ * Since: 1.4
+ */
+void
+clutter_deform_effect_invalidate (ClutterDeformEffect *effect)
+{
+ ClutterActor *actor;
+
+ g_return_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect));
+
+ if (effect->priv->is_dirty)
+ return;
+
+ effect->priv->is_dirty = TRUE;
+
+ actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
+ if (actor != NULL)
+ clutter_actor_queue_redraw (actor);
+}
diff --git a/clutter/clutter-deform-effect.h b/clutter/clutter-deform-effect.h
new file mode 100644
index 000000000..63ccd4c5a
--- /dev/null
+++ b/clutter/clutter-deform-effect.h
@@ -0,0 +1,111 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * 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, see .
+ *
+ * Author:
+ * Emmanuele Bassi
+ */
+
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#ifndef __CLUTTER_DEFORM_EFFECT_H__
+#define __CLUTTER_DEFORM_EFFECT_H__
+
+#include
+#include
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_DEFORM_EFFECT (clutter_deform_effect_get_type ())
+#define CLUTTER_DEFORM_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEFORM_EFFECT, ClutterDeformEffect))
+#define CLUTTER_IS_DEFORM_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEFORM_EFFECT))
+#define CLUTTER_DEFORM_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEFORM_EFFECT, ClutterDeformEffectClass))
+#define CLUTTER_IS_DEFORM_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DEFORM_EFFECT))
+#define CLUTTER_DEFORM_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DEFORM_EFFECT, ClutterDeformEffectClass))
+
+typedef struct _ClutterDeformEffect ClutterDeformEffect;
+typedef struct _ClutterDeformEffectPrivate ClutterDeformEffectPrivate;
+typedef struct _ClutterDeformEffectClass ClutterDeformEffectClass;
+
+/**
+ * ClutterDeformEffect:
+ *
+ * The ClutterDeformEffect structure contains
+ * only private data and should be accessed using the provided API
+ *
+ * Since: 1.4
+ */
+struct _ClutterDeformEffect
+{
+ /*< private >*/
+ ClutterOffscreenEffect parent_instance;
+
+ ClutterDeformEffectPrivate *priv;
+};
+
+/**
+ * ClutterDeformEffectClass:
+ * @deform_vertex: virtual function; sub-classes should override this
+ * function to compute the deformation of each vertex
+ *
+ * The ClutterDeformEffectClass structure contains
+ * only private data
+ *
+ * Since: 1.4
+ */
+struct _ClutterDeformEffectClass
+{
+ /*< private >*/
+ ClutterOffscreenEffectClass parent_class;
+
+ /*< public >*/
+ void (* deform_vertex) (ClutterDeformEffect *effect,
+ gfloat width,
+ gfloat height,
+ CoglTextureVertex *vertex);
+
+ /*< private >*/
+ void (*_clutter_deform1) (void);
+ void (*_clutter_deform2) (void);
+ void (*_clutter_deform3) (void);
+ void (*_clutter_deform4) (void);
+ void (*_clutter_deform5) (void);
+ void (*_clutter_deform6) (void);
+ void (*_clutter_deform7) (void);
+};
+
+GType clutter_deform_effect_get_type (void) G_GNUC_CONST;
+
+void clutter_deform_effect_set_back_material (ClutterDeformEffect *effect,
+ CoglHandle material);
+CoglHandle clutter_deform_effect_get_back_material (ClutterDeformEffect *effect);
+void clutter_deform_effect_set_n_tiles (ClutterDeformEffect *effect,
+ guint x_tiles,
+ guint y_tiles);
+void clutter_deform_effect_get_n_tiles (ClutterDeformEffect *effect,
+ guint *x_tiles,
+ guint *y_tiles);
+
+void clutter_deform_effect_invalidate (ClutterDeformEffect *effect);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_DEFORM_EFFECT_H__ */
diff --git a/clutter/clutter-effect.c b/clutter/clutter-effect.c
index 0dd781b97..c89f33251 100644
--- a/clutter/clutter-effect.c
+++ b/clutter/clutter-effect.c
@@ -39,29 +39,17 @@
*
* Implementing a ClutterEffect
* Creating a sub-class of #ClutterEffect requires the implementation
- * of three virtual functions:
+ * of two virtual functions:
*
- * prepare(), which is called when
- * attaching the #ClutterEffect to a #ClutterActor through the
- * clutter_actor_add_effect() function or when the actor is being
- * painted;
* pre_paint(), which is called
* before painting the #ClutterActor.
* post_paint(), which is called
* after painting the #ClutterActor.
*
- * The prepare() function receives the
- * #ClutterActor to which the effect has been attached to, and it should be
- * used to set up the initial state of the effect, for instance depending on
- * the actor that has been passed. The function returns a boolean value,
- * which is used to determine whether the #ClutterEffect has been prepared or
- * not. An unprepared shader will be asked to prepare itself again during the
- * actor's paint sequence, and if it fails again it will be ignored.
* The pre_paint() function should be used to set
* up the #ClutterEffect right before the #ClutterActor's paint
- * sequence. This function, like prepare() can fail, and
- * return %FALSE; in that case, no post_paint()
- * invocation will follow.
+ * sequence. This function can fail, and return %FALSE; in that case, no
+ * post_paint() invocation will follow.
* The post_paint() function is called after the
* #ClutterActor's paint sequence.
* The pre_paint() phase could be seen as a custom
@@ -73,8 +61,8 @@
* A simple ClutterEffect implementation
* The example below creates two rectangles: one will be painted
* "behind" the actor, while another will be painted "on top" of the actor.
- * The prepare() phase will create the two materials
- * used for the two different rectangles; the
+ * The set_actor() implementation will create the two
+ * materials used for the two different rectangles; the
* pre_paint() function will paint the first material
* using cogl_rectangle(), while the post_paint()
* phase will paint the second material.
diff --git a/clutter/clutter-offscreen-effect.c b/clutter/clutter-offscreen-effect.c
index e3ce81752..009d44d80 100644
--- a/clutter/clutter-offscreen-effect.c
+++ b/clutter/clutter-offscreen-effect.c
@@ -316,12 +316,12 @@ clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect)
/* paint the texture at the same position as the actor would be,
* in Stage coordinates, since we set up the modelview matrix to
- * be exactly as the stage sets it up
+ * be exactly as the stage sets it up, plus the eventual offsets
+ * due to offscreen effects stacking
*/
- cogl_rectangle_with_texture_coords (priv->x_offset,
- priv->y_offset,
- priv->x_offset + priv->target_width,
- priv->y_offset + priv->target_height,
+ cogl_rectangle_with_texture_coords (0, 0,
+ priv->target_width,
+ priv->target_height,
0.0, 0.0,
1.0, 1.0);
}
@@ -364,6 +364,8 @@ clutter_offscreen_effect_post_paint (ClutterEffect *effect)
cogl_push_matrix ();
+ cogl_translate (priv->x_offset, priv->y_offset, 0.0f);
+
/* paint the target material; this is virtualized for
* sub-classes that require special hand-holding
*/
diff --git a/clutter/clutter-page-turn-effect.c b/clutter/clutter-page-turn-effect.c
new file mode 100644
index 000000000..4c8227a7f
--- /dev/null
+++ b/clutter/clutter-page-turn-effect.c
@@ -0,0 +1,417 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * 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, see .
+ *
+ * Author:
+ * Emmanuele Bassi
+ *
+ * Based on MxDeformPageTurn, written by:
+ * Chris Lord
+ */
+
+/**
+ * SECTION:clutter-page-turn-effect
+ * @Title: ClutterPageTurnEffect
+ * @Short_Description: A page turning effect
+ *
+ * A simple page turning effect
+ *
+ * #ClutterPageTurnEffect is available since Clutter 1.4
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter-page-turn-effect.h"
+
+#include "clutter-debug.h"
+#include "clutter-private.h"
+
+#define CLUTTER_PAGE_TURN_EFFECT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CLUTTER_TYPE_PAGE_TURN_EFFECT, ClutterPageTurnEffectClass))
+#define CLUTTER_IS_PAGE_TURN_EFFECT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CLUTTER_TYPE_PAGE_TURN_EFFECT))
+#define CLUTTER_PAGE_TURN_EFFECT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CLUTTER_TYPE_PAGE_TURN_EFFECT, ClutterPageTurnEffectClass))
+
+typedef struct _ClutterPageTurnEffectClass ClutterPageTurnEffectClass;
+
+struct _ClutterPageTurnEffect
+{
+ ClutterDeformEffect parent_instance;
+
+ gdouble period;
+ gdouble angle;
+
+ gfloat radius;
+};
+
+struct _ClutterPageTurnEffectClass
+{
+ ClutterDeformEffectClass parent_class;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_PERIOD,
+ PROP_ANGLE,
+ PROP_RADIUS
+};
+
+G_DEFINE_TYPE (ClutterPageTurnEffect,
+ clutter_page_turn_effect,
+ CLUTTER_TYPE_DEFORM_EFFECT);
+
+static void
+clutter_page_turn_effect_deform_vertex (ClutterDeformEffect *effect,
+ gfloat width,
+ gfloat height,
+ CoglTextureVertex *vertex)
+{
+ ClutterPageTurnEffect *self = CLUTTER_PAGE_TURN_EFFECT (effect);
+ gfloat cx, cy, rx, ry, radians, turn_angle;
+ guint shade;
+
+ if (self->period == 0.0)
+ return;
+
+ radians = self->angle * 180.0f / G_PI;
+
+ /* Rotate the point around the centre of the page-curl ray to align it with
+ * the y-axis.
+ */
+ cx = (1.f - self->period) * width;
+ cy = (1.f - self->period) * height;
+
+ rx = ((vertex->x - cx) * cos (- radians))
+ - ((vertex->y - cy) * sin (- radians))
+ - self->radius;
+ ry = ((vertex->x - cx) * sin (- radians))
+ + ((vertex->y - cy) * cos (- radians));
+
+ turn_angle = 0.f;
+ if (rx > self->radius * -2.0f)
+ {
+ /* Calculate the curl angle as a function from the distance of the curl
+ * ray (i.e. the page crease)
+ */
+ turn_angle = (rx / self->radius * G_PI_2) - G_PI_2;
+ shade = (sin (turn_angle) * 96.0f) + 159.0f;
+
+ /* Add a gradient that makes it look like lighting and hides the switch
+ * between textures.
+ */
+ cogl_color_set_from_4ub (&vertex->color, shade, shade, shade, 0xff);
+ }
+
+ if (rx > 0)
+ {
+ /* Make the curl radius smaller as more circles are formed (stops
+ * z-fighting and looks cool). Note that 10 is a semi-arbitrary
+ * number here - divide it by two and it's the amount of space
+ * between curled layers of the texture, in pixels.
+ */
+ gfloat small_radius;
+
+ small_radius = self->radius
+ - MIN (self->radius, (turn_angle * 10) / G_PI);
+
+ /* Calculate a point on a cylinder (maybe make this a cone at some
+ * point) and rotate it by the specified angle.
+ */
+ rx = (small_radius * cos (turn_angle)) + self->radius;
+
+ vertex->x = (rx * cos (radians)) - (ry * sin (radians)) + cx;
+ vertex->y = (rx * sin (radians)) + (ry * cos (radians)) + cy;
+ vertex->z = (small_radius * sin (turn_angle)) + self->radius;
+ }
+}
+
+static void
+clutter_page_turn_effect_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterPageTurnEffect *effect = CLUTTER_PAGE_TURN_EFFECT (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_PERIOD:
+ clutter_page_turn_effect_set_period (effect, g_value_get_double (value));
+ break;
+
+ case PROP_ANGLE:
+ clutter_page_turn_effect_set_angle (effect, g_value_get_double (value));
+ break;
+
+ case PROP_RADIUS:
+ clutter_page_turn_effect_set_radius (effect, g_value_get_float (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+clutter_page_turn_effect_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterPageTurnEffect *effect = CLUTTER_PAGE_TURN_EFFECT (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_PERIOD:
+ g_value_set_double (value, effect->period);
+ break;
+
+ case PROP_ANGLE:
+ g_value_set_double (value, effect->angle);
+ break;
+
+ case PROP_RADIUS:
+ g_value_set_float (value, effect->radius);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+clutter_page_turn_effect_class_init (ClutterPageTurnEffectClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ ClutterDeformEffectClass *deform_class = CLUTTER_DEFORM_EFFECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ gobject_class->set_property = clutter_page_turn_effect_set_property;
+ gobject_class->get_property = clutter_page_turn_effect_get_property;
+
+ /**
+ * ClutterPageTurnEffect:period:
+ *
+ * The period of the page turn, between 0.0 (no curling) and
+ * 1.0 (fully curled)
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_double ("period",
+ "Period",
+ "The period of the page turn",
+ 0.0, 1.0,
+ 0.0,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_PERIOD, pspec);
+
+ /**
+ * ClutterPageTurnEffect:angle:
+ *
+ * The angle of the page rotation, in degrees, between 0.0 and 360.0
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_double ("angle",
+ "Angle",
+ "The angle of the page rotation, in degrees",
+ 0.0, 360.0,
+ 0.0,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_ANGLE, pspec);
+
+ /**
+ * ClutterPageTurnEffect:radius:
+ *
+ * The radius of the page curl, in pixels
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_float ("radius",
+ "Radius",
+ "The radius of the page curl",
+ -G_MAXFLOAT, G_MAXFLOAT,
+ 24.0,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_RADIUS, pspec);
+
+ deform_class->deform_vertex = clutter_page_turn_effect_deform_vertex;
+}
+
+static void
+clutter_page_turn_effect_init (ClutterPageTurnEffect *self)
+{
+ self->period = 0.0;
+ self->angle = 0.0;
+ self->radius = 24.0f;
+}
+
+/**
+ * clutter_page_turn_effect_new:
+ * @period: the period of the page curl, between 0.0 and 1.0
+ * @angle: the angle of the page curl, between 0.0 and 360.0
+ * @radius: the radius of the page curl, in pixels
+ *
+ * Creates a new #ClutterPageTurnEffect instance with the given parameters
+ *
+ * Return value: the newly created #ClutterPageTurnEffect
+ *
+ * Since: 1.4
+ */
+ClutterEffect *
+clutter_page_turn_effect_new (gdouble period,
+ gdouble angle,
+ gfloat radius)
+{
+ g_return_val_if_fail (period >= 0.0 && period <= 1.0, NULL);
+ g_return_val_if_fail (angle >= 0.0 && angle <= 360.0, NULL);
+
+ return g_object_new (CLUTTER_TYPE_PAGE_TURN_EFFECT,
+ "period", period,
+ "angle", angle,
+ "radius", radius,
+ NULL);
+}
+
+/**
+ * clutter_page_turn_effect_set_period:
+ * @effect: a #ClutterPageTurnEffect
+ * @period: the period of the page curl, between 0.0 and 1.0
+ *
+ * Sets the period of the page curling, between 0.0 (no curling)
+ * and 1.0 (fully curled)
+ *
+ * Since: 1.4
+ */
+void
+clutter_page_turn_effect_set_period (ClutterPageTurnEffect *effect,
+ gdouble period)
+{
+ g_return_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect));
+ g_return_if_fail (period >= 0.0 && period <= 1.0);
+
+ effect->period = period;
+
+ clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect));
+
+ g_object_notify (G_OBJECT (effect), "period");
+}
+
+/**
+ * clutter_page_turn_effect_get_period:
+ * @effect: a #ClutterPageTurnEffect
+ *
+ * Retrieves the value set using clutter_page_turn_effect_get_period()
+ *
+ * Return value: the period of the page curling
+ *
+ * Since: 1.4
+ */
+gdouble
+clutter_page_turn_effect_get_period (ClutterPageTurnEffect *effect)
+{
+ g_return_val_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect), 0.0);
+
+ return effect->period;
+}
+
+/**
+ * clutter_page_turn_effect_set_angle:
+ * @effect: #ClutterPageTurnEffect
+ * @angle: the angle of the page curl, in degrees
+ *
+ * Sets the angle of the page curling, in degrees
+ *
+ * Since: 1.4
+ */
+void
+clutter_page_turn_effect_set_angle (ClutterPageTurnEffect *effect,
+ gdouble angle)
+{
+ g_return_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect));
+ g_return_if_fail (angle >= 0.0 && angle <= 360.0);
+
+ effect->angle = angle;
+
+ clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect));
+
+ g_object_notify (G_OBJECT (effect), "angle");
+}
+
+/**
+ * clutter_page_turn_effect_get_angle:
+ * @effect: a #ClutterPageTurnEffect:
+ *
+ * Retrieves the value set using clutter_page_turn_effect_get_angle()
+ *
+ * Return value: the angle of the page curling
+ *
+ * Since: 1.4
+ */
+gdouble
+clutter_page_turn_effect_get_angle (ClutterPageTurnEffect *effect)
+{
+ g_return_val_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect), 0.0);
+
+ return effect->angle;
+}
+
+/**
+ * clutter_page_turn_effect_set_radius:
+ * @effect: a #ClutterPageTurnEffect:
+ * @radius: the radius of the page curling, in pixels
+ *
+ * Sets the radius of the page curling
+ *
+ * Since: 1.4
+ */
+void
+clutter_page_turn_effect_set_radius (ClutterPageTurnEffect *effect,
+ gfloat radius)
+{
+ g_return_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect));
+
+ effect->radius = radius;
+
+ clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect));
+
+ g_object_notify (G_OBJECT (effect), "radius");
+}
+
+/**
+ * clutter_page_turn_effect_get_radius:
+ * @effect: a #ClutterPageTurnEffect
+ *
+ * Retrieves the value set using clutter_page_turn_effect_set_radius()
+ *
+ * Return value: the radius of the page curling
+ *
+ * Since: 1.4
+ */
+gfloat
+clutter_page_turn_effect_get_radius (ClutterPageTurnEffect *effect)
+{
+ g_return_val_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect), 0.0);
+
+ return effect->radius;
+}
diff --git a/clutter/clutter-page-turn-effect.h b/clutter/clutter-page-turn-effect.h
new file mode 100644
index 000000000..ca95fb824
--- /dev/null
+++ b/clutter/clutter-page-turn-effect.h
@@ -0,0 +1,71 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * 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, see .
+ *
+ * Author:
+ * Emmanuele Bassi
+ *
+ * Based on MxDeformPageTurn, written by:
+ * Chris Lord
+ */
+
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#ifndef __CLUTTER_PAGE_TURN_EFFECT_H__
+#define __CLUTTER_PAGE_TURN_EFFECT_H__
+
+#include
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_PAGE_TURN_EFFECT (clutter_page_turn_effect_get_type ())
+#define CLUTTER_PAGE_TURN_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_PAGE_TURN_EFFECT, ClutterPageTurnEffect))
+#define CLUTTER_IS_PAGE_TURN_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_PAGE_TURN_EFFECT))
+
+/**
+ * ClutterPageTurnEffect:
+ *
+ * ClutterPageTurnEffect is an opaque structure
+ * whose members can only be accessed using the provided API
+ *
+ * Since: 1.4
+ */
+typedef struct _ClutterPageTurnEffect ClutterPageTurnEffect;
+
+GType clutter_page_turn_effect_get_type (void) G_GNUC_CONST;
+
+ClutterEffect *clutter_page_turn_effect_new (gdouble period,
+ gdouble angle,
+ gfloat radius);
+
+void clutter_page_turn_effect_set_period (ClutterPageTurnEffect *effect,
+ gdouble period);
+gdouble clutter_page_turn_effect_get_period (ClutterPageTurnEffect *effect);
+void clutter_page_turn_effect_set_angle (ClutterPageTurnEffect *effect,
+ gdouble angle);
+gdouble clutter_page_turn_effect_get_angle (ClutterPageTurnEffect *effect);
+void clutter_page_turn_effect_set_radius (ClutterPageTurnEffect *effect,
+ gfloat radius);
+gfloat clutter_page_turn_effect_get_radius (ClutterPageTurnEffect *effect);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_PAGE_TURN_EFFECT_H__ */
diff --git a/clutter/clutter.h b/clutter/clutter.h
index 0b948af95..3f64f0945 100644
--- a/clutter/clutter.h
+++ b/clutter/clutter.h
@@ -60,6 +60,7 @@
#include "clutter-colorize-effect.h"
#include "clutter-constraint.h"
#include "clutter-container.h"
+#include "clutter-deform-effect.h"
#include "clutter-desaturate-effect.h"
#include "clutter-device-manager.h"
#include "clutter-drag-action.h"
@@ -80,6 +81,7 @@
#include "clutter-media.h"
#include "clutter-model.h"
#include "clutter-offscreen-effect.h"
+#include "clutter-page-turn-effect.h"
#include "clutter-path.h"
#include "clutter-rectangle.h"
#include "clutter-score.h"
diff --git a/doc/reference/clutter/clutter-docs.xml.in b/doc/reference/clutter/clutter-docs.xml.in
index 2a6b7065b..6433f790e 100644
--- a/doc/reference/clutter/clutter-docs.xml.in
+++ b/doc/reference/clutter/clutter-docs.xml.in
@@ -106,6 +106,8 @@
+
+
diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt
index 49f5ceb44..873224f06 100644
--- a/doc/reference/clutter/clutter-sections.txt
+++ b/doc/reference/clutter/clutter-sections.txt
@@ -2403,3 +2403,43 @@ CLUTTER_IS_DESATURATE_EFFECT
clutter_desaturate_effect_get_type
+
+
+clutter-deform-effect
+ClutterDeformEffect
+ClutterDeformEffectClass
+clutter_deform_effect_set_back_material
+clutter_deform_effect_get_back_material
+clutter_deform_effect_set_n_tiles
+clutter_deform_effect_get_n_tiles
+
+clutter_deform_effect_invalidate
+
+CLUTTER_TYPE_DEFORM_EFFECT
+CLUTTER_DEFORM_EFFECT
+CLUTTER_DEFORM_EFFECT_CLASS
+CLUTTER_IS_DEFORM_EFFECT
+CLUTTER_IS_DEFORM_EFFECT_CLASS
+CLUTTER_DEFORM_EFFECT_GET_CLASS
+
+ClutterDeformEffectPrivate
+clutter_deform_effect_get_type
+
+
+
+clutter-page-turn-effect
+ClutterPageTurnEffect
+clutter_page_turn_effect_new
+clutter_page_turn_effect_set_period
+clutter_page_turn_effect_get_period
+clutter_page_turn_effect_set_angle
+clutter_page_turn_effect_get_angle
+clutter_page_turn_effect_set_radius
+clutter_page_turn_effect_get_radius
+
+CLUTTER_TYPE_PAGE_TURN_EFFECT
+CLUTTER_PAGE_TURN_EFFECT
+CLUTTER_IS_PAGE_TURN_EFFECT
+
+clutter_page_turn_effect_get_type
+
diff --git a/doc/reference/clutter/clutter.types b/doc/reference/clutter/clutter.types
index 517b72f32..9e22d5c38 100644
--- a/doc/reference/clutter/clutter.types
+++ b/doc/reference/clutter/clutter.types
@@ -27,6 +27,7 @@ clutter_click_action_get_type
clutter_clone_get_type
clutter_colorize_effect_get_type
clutter_constraint_get_type
+clutter_deform_effect_get_type
clutter_desaturate_effect_get_type
clutter_device_manager_get_type
clutter_drag_action_get_type
@@ -43,6 +44,7 @@ clutter_media_get_type
clutter_model_get_type
clutter_model_iter_get_type
clutter_offscreen_effect_get_type
+clutter_page_turn_effect_get_type
clutter_path_get_type
clutter_rectangle_get_type
clutter_score_get_type
diff --git a/tests/interactive/test-drag.c b/tests/interactive/test-drag.c
index 08197c319..7fda1a552 100644
--- a/tests/interactive/test-drag.c
+++ b/tests/interactive/test-drag.c
@@ -2,6 +2,28 @@
#include
#include
+static gboolean
+on_enter (ClutterActor *actor,
+ ClutterEvent *event)
+{
+ clutter_actor_animate (actor, CLUTTER_LINEAR, 150,
+ "@effects.curl.period", 0.25,
+ NULL);
+
+ return FALSE;
+}
+
+static gboolean
+on_leave (ClutterActor *actor,
+ ClutterEvent *event)
+{
+ clutter_actor_animate (actor, CLUTTER_LINEAR, 150,
+ "@effects.curl.period", 0.0,
+ NULL);
+
+ return FALSE;
+}
+
static void
on_drag_begin (ClutterDragAction *action,
ClutterActor *actor,
@@ -156,6 +178,8 @@ test_drag_main (int argc, char *argv[])
clutter_actor_set_position (handle, (800 - 128) / 2, (600 - 128) / 2);
clutter_actor_set_reactive (handle, TRUE);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), handle);
+ g_signal_connect (handle, "enter-event", G_CALLBACK (on_enter), NULL);
+ g_signal_connect (handle, "leave-event", G_CALLBACK (on_leave), NULL);
action = clutter_drag_action_new ();
clutter_drag_action_set_drag_threshold (CLUTTER_DRAG_ACTION (action),
@@ -169,6 +193,7 @@ test_drag_main (int argc, char *argv[])
clutter_actor_add_action (handle, action);
clutter_actor_add_effect_with_name (handle, "disable", clutter_desaturate_effect_new (0.0));
+ clutter_actor_add_effect_with_name (handle, "curl", clutter_page_turn_effect_new (0.0, 135.0, 12.0));
clutter_actor_show (stage);