diff --git a/clutter/Makefile.am b/clutter/Makefile.am
index c514406ff..e658c58f6 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 \
@@ -182,6 +183,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 \
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.h b/clutter/clutter.h
index 0b948af95..70c8fa37b 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"