Add the ClutterEffect abstract class
authorEmmanuele Bassi <ebassi@linux.intel.com>
Thu, 8 Apr 2010 09:55:15 +0000 (10:55 +0100)
committerEmmanuele Bassi <ebassi@linux.intel.com>
Thu, 3 Jun 2010 13:10:55 +0000 (14:10 +0100)
ClutterEffect is an abstract class that should be used to apply effects
on generic actors.

The ClutterEffect class just defines what an effect should implement; it
could be defined as an interface, but we might want to add some default
behavior dependent on the internal state at a later point.

The effect API applies to any actor, so we need to provide a way to
assign an effect to an actor, and let ClutterActor call the Effect
methods during the paint sequence.

Once an effect is attached to an actor we will perform the paint in this
order:

  • Effect::pre_paint()
  • Actor::paint signal emission
  • Effect::post_paint()

Since an effect might collide with the Shader class, we either allow a
shader or an effect for the time being.

clutter/Makefile.am
clutter/clutter-actor.c
clutter/clutter-actor.h
clutter/clutter-effect.c [new file with mode: 0644]
clutter/clutter-effect.h [new file with mode: 0644]
clutter/clutter-private.h
clutter/clutter.h
tests/interactive/test-rotate.c

index 7fac70e..676df67 100644 (file)
@@ -96,6 +96,7 @@ source_h =                                    \
        $(srcdir)/clutter-deprecated.h          \
        $(srcdir)/clutter-device-manager.h      \
        $(srcdir)/clutter-drag-action.h         \
+       $(srcdir)/clutter-effect.h              \
        $(srcdir)/clutter-event.h               \
        $(srcdir)/clutter-feature.h             \
        $(srcdir)/clutter-fixed.h               \
@@ -177,6 +178,7 @@ source_c = \
        $(srcdir)/clutter-container.c           \
        $(srcdir)/clutter-device-manager.c      \
        $(srcdir)/clutter-drag-action.c         \
+       $(srcdir)/clutter-effect.c              \
        clutter-enum-types.c                    \
        $(srcdir)/clutter-event.c               \
        $(srcdir)/clutter-feature.c             \
@@ -225,14 +227,14 @@ source_h_priv = \
        $(srcdir)/clutter-actor-meta-private.h  \
        $(srcdir)/clutter-bezier.h              \
        $(srcdir)/clutter-debug.h               \
+       $(srcdir)/clutter-id-pool.h             \
        $(srcdir)/clutter-keysyms-table.h       \
        $(srcdir)/clutter-master-clock.h        \
        $(srcdir)/clutter-model-private.h       \
        $(srcdir)/clutter-private.h             \
-       $(srcdir)/clutter-id-pool.h             \
+       $(srcdir)/clutter-profile.h             \
        $(srcdir)/clutter-script-private.h      \
        $(srcdir)/clutter-timeout-interval.h    \
-       $(srcdir)/clutter-profile.h             \
        $(NULL)
 
 libclutter_@CLUTTER_WINSYS@_@CLUTTER_API_VERSION@_la_LIBADD = \
index 1cc8453..2766b65 100644 (file)
 #include "config.h"
 #endif
 
+#include "cogl/cogl.h"
+
 #include "clutter-actor.h"
 
 #include "clutter-action.h"
 #include "clutter-constraint.h"
 #include "clutter-container.h"
 #include "clutter-debug.h"
+#include "clutter-effect.h"
 #include "clutter-enum-types.h"
 #include "clutter-main.h"
 #include "clutter-marshal.h"
 #include "clutter-stage.h"
 #include "clutter-units.h"
 
-#include "cogl/cogl.h"
-
 typedef struct _ShaderData ShaderData;
 typedef struct _AnchorCoord AnchorCoord;
 
@@ -459,6 +460,7 @@ struct _ClutterActorPrivate
 
   ClutterMetaGroup *actions;
   ClutterMetaGroup *constraints;
+  ClutterMetaGroup *effects;
 };
 
 enum
@@ -542,7 +544,8 @@ enum
   PROP_HAS_POINTER,
 
   PROP_ACTIONS,
-  PROP_CONSTRAINTS
+  PROP_CONSTRAINTS,
+  PROP_EFFECT
 };
 
 enum
@@ -1803,10 +1806,11 @@ clutter_actor_real_queue_redraw (ClutterActor *self,
     {
       ClutterActor *stage = clutter_actor_get_stage_internal (self);
 
-      if (stage != NULL&&
+      if (stage != NULL &&
           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
         return;
     }
+
   self->priv->propagated_one_redraw = TRUE;
 
   /* notify parents, if they are all visible eventually we'll
@@ -1887,8 +1891,8 @@ full_vertex_transform (const CoglMatrix *matrix,
 /* Help macros to scale from OpenGL <-1,1> coordinates system to our
  * X-window based <0,window-size> coordinates
  */
-#define MTX_GL_SCALE_X(x,w,v1,v2)       ((((((x) / (w)) + 1.0) / 2) * (v1)) + (v2))
-#define MTX_GL_SCALE_Y(y,w,v1,v2)       ((v1) - (((((y) / (w)) + 1.0) / 2) * (v1)) + (v2))
+#define MTX_GL_SCALE_X(x,w,v1,v2)       ((((((x) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
+#define MTX_GL_SCALE_Y(y,w,v1,v2)       ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
 #define MTX_GL_SCALE_Z(z,w,v1,v2)       (MTX_GL_SCALE_X ((z), (w), (v1), (v2)))
 
 /* scales a fixed @vertex using @matrix and @viewport, and
@@ -1905,11 +1909,7 @@ full_vertex_scale (const CoglMatrix    *matrix,
 
   tmp = *vertex;
 
-  cogl_matrix_transform_point (matrix,
-                               &tmp.x,
-                               &tmp.y,
-                               &tmp.z,
-                               &tmp.w);
+  cogl_matrix_transform_point (matrix, &tmp.x, &tmp.y, &tmp.z, &tmp.w);
 
   v_x      = viewport[0];
   v_y      = viewport[1];
@@ -2222,7 +2222,7 @@ _clutter_actor_get_relative_modelview (ClutterActor *self,
 
   if (ancestor == NULL)
     {
-      stage = clutter_actor_get_stage (self);
+      stage = clutter_actor_get_stage_internal (self);
 
       clutter_stage_get_perspective (CLUTTER_STAGE (stage), &perspective);
       cogl_perspective (perspective.fovy,
@@ -2256,6 +2256,7 @@ _clutter_actor_get_relative_modelview (ClutterActor *self,
           cogl_matrix_init_identity (&identity);
           initialized_identity = TRUE;
         }
+
       cogl_set_modelview_matrix (&identity);
     }
 
@@ -2273,8 +2274,8 @@ _clutter_actor_get_relative_modelview (ClutterActor *self,
  */
 void
 _clutter_actor_get_projection_and_viewport (ClutterActor *self,
-                                            CoglMatrix *matrix,
-                                            float *viewport)
+                                            CoglMatrix   *matrix,
+                                            float        *viewport)
 {
   _clutter_actor_ensure_stage_current (self);
 
@@ -2428,8 +2429,8 @@ void
 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
                                            ClutterVertex  verts[])
 {
-  ClutterActorPrivate   *priv;
-  ClutterActorBox        actor_space_allocation;
+  ClutterActorPrivate *priv;
+  ClutterActorBox actor_space_allocation;
 
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
@@ -2456,10 +2457,8 @@ clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
    * own coordinate space... */
   actor_space_allocation.x1 = 0;
   actor_space_allocation.y1 = 0;
-  actor_space_allocation.x2 =
-    self->priv->allocation.x2 - self->priv->allocation.x1;
-  actor_space_allocation.y2 =
-    self->priv->allocation.y2 - self->priv->allocation.y1;
+  actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
+  actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
   _clutter_actor_transform_and_project_box (self,
                                            &actor_space_allocation,
                                            verts);
@@ -2551,6 +2550,40 @@ _clutter_actor_apply_modelview_transform (ClutterActor *self)
   cogl_set_modelview_matrix (&new);
 }
 
+static gboolean
+_clutter_actor_effects_pre_paint (ClutterActor *self)
+{
+  ClutterActorPrivate *priv = self->priv;
+  const GList *effects, *l;
+  gboolean was_pre_painted = FALSE;
+
+  effects = _clutter_meta_group_peek_metas (priv->effects);
+  for (l = effects; l != NULL; l = l->next)
+    {
+      ClutterEffect *effect = l->data;
+
+      was_pre_painted |= _clutter_effect_pre_paint (effect);
+    }
+
+  return was_pre_painted;
+}
+
+static void
+_clutter_actor_effects_post_paint (ClutterActor *self)
+{
+  ClutterActorPrivate *priv = self->priv;
+  const GList *effects, *l;
+
+  /* we walk the list backwards, to unwind the post-paint order */
+  effects = _clutter_meta_group_peek_metas (priv->effects);
+  for (l = g_list_last ((GList *) effects); l != NULL; l = l->prev)
+    {
+      ClutterEffect *effect = l->data;
+
+      _clutter_effect_post_paint (effect);
+    }
+}
+
 /* Recursively applies the transforms associated with this actor and
  * its ancestors to the OpenGL modelview matrix. Use NULL if you want this
  * to go all the way down to the stage.
@@ -2669,14 +2702,22 @@ clutter_actor_paint (ClutterActor *self)
 
   if (context->pick_mode == CLUTTER_PICK_NONE)
     {
+      gboolean effect_painted = FALSE;
+
       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
 
-      clutter_actor_shader_pre_paint (self, FALSE);
+      if (priv->effects != NULL)
+        effect_painted = _clutter_actor_effects_pre_paint (self);
+      else if (priv->shader_data != NULL)
+        clutter_actor_shader_pre_paint (self, FALSE);
 
-      self->priv->propagated_one_redraw = FALSE;
+      priv->propagated_one_redraw = FALSE;
       g_signal_emit (self, actor_signals[PAINT], 0);
 
-      clutter_actor_shader_post_paint (self);
+      if (effect_painted)
+        _clutter_actor_effects_post_paint (self);
+      else if (priv->shader_data != NULL)
+        clutter_actor_shader_post_paint (self);
     }
   else
     {
@@ -3016,6 +3057,10 @@ clutter_actor_set_property (GObject      *object,
       clutter_actor_add_constraint (actor, g_value_get_object (value));
       break;
 
+    case PROP_EFFECT:
+      clutter_actor_add_effect (actor, g_value_get_object (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -3323,7 +3368,7 @@ clutter_actor_dispose (GObject *object)
 
   destroy_shader_data (self);
 
-  if (priv->pango_context != NULL)
+  if (priv->pango_context)
     {
       g_object_unref (priv->pango_context);
       priv->pango_context = NULL;
@@ -3335,6 +3380,12 @@ clutter_actor_dispose (GObject *object)
       priv->actions = NULL;
     }
 
+  if (priv->effects != NULL)
+    {
+      g_object_unref (priv->effects);
+      priv->effects = NULL;
+    }
+
   g_signal_emit (self, actor_signals[DESTROY], 0);
 
   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
@@ -4210,6 +4261,20 @@ clutter_actor_class_init (ClutterActorClass *klass)
   g_object_class_install_property (object_class, PROP_CONSTRAINTS, pspec);
 
   /**
+   * ClutterActor:effect:
+   *
+   * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
+   *
+   * Since: 1.4
+   */
+  pspec = g_param_spec_object ("effect",
+                               "Effect",
+                               "Add an effect to be applied on the actor",
+                               CLUTTER_TYPE_EFFECT,
+                               CLUTTER_PARAM_WRITABLE);
+  g_object_class_install_property (object_class, PROP_EFFECT, pspec);
+
+  /**
    * ClutterActor::destroy:
    * @actor: the object which received the signal
    *
@@ -10996,3 +11061,212 @@ clutter_actor_get_clip_to_allocation (ClutterActor *self)
 
   return self->priv->clip_to_allocation;
 }
+
+/**
+ * clutter_actor_add_effect:
+ * @self: a #ClutterActor
+ * @effect: a #ClutterEffect
+ *
+ * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
+ *
+ * The #ClutterActor will hold a reference on the @effect until either
+ * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
+ * called.
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_add_effect (ClutterActor  *self,
+                          ClutterEffect *effect)
+{
+  ClutterActorPrivate *priv;
+
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+  g_return_if_fail (CLUTTER_IS_EFFECT (effect));
+
+  priv = self->priv;
+
+  if (priv->effects == NULL)
+    {
+      priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
+      priv->effects->actor = self;
+    }
+
+  _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
+
+  clutter_actor_queue_redraw (self);
+
+  g_object_notify (G_OBJECT (self), "effect");
+}
+
+/**
+ * clutter_actor_add_effect_with_name:
+ * @self: a #ClutterActor
+ * @name: the name to set on the effect
+ * @effect: a #ClutterEffect
+ *
+ * A convenience function for setting the name of a #ClutterEffect
+ * while adding it to the list of effectss applied to @self
+ *
+ * This function is the logical equivalent of:
+ *
+ * |[
+ *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
+ *   clutter_actor_add_effect (self, effect);
+ * ]|
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_add_effect_with_name (ClutterActor  *self,
+                                    const gchar   *name,
+                                    ClutterEffect *effect)
+{
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+  g_return_if_fail (name != NULL);
+  g_return_if_fail (CLUTTER_IS_EFFECT (effect));
+
+  clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
+  clutter_actor_add_effect (self, effect);
+}
+
+/**
+ * clutter_actor_remove_effect:
+ * @self: a #ClutterActor
+ * @effect: a #ClutterEffect
+ *
+ * Removes @effect from the list of effects applied to @self
+ *
+ * The reference held by @self on the #ClutterEffect will be released
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_remove_effect (ClutterActor  *self,
+                             ClutterEffect *effect)
+{
+  ClutterActorPrivate *priv;
+
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+  g_return_if_fail (CLUTTER_IS_EFFECT (effect));
+
+  priv = self->priv;
+
+  if (priv->effects == NULL)
+    return;
+
+  _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
+
+  clutter_actor_queue_redraw (self);
+
+  g_object_notify (G_OBJECT (self), "effect");
+}
+
+/**
+ * clutter_actor_remove_effect_by_name:
+ * @self: a #ClutterActor
+ * @name: the name of the effect to remove
+ *
+ * Removes the #ClutterEffect with the given name from the list
+ * of effects applied to @self
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_remove_effect_by_name (ClutterActor *self,
+                                     const gchar  *name)
+{
+  ClutterActorPrivate *priv;
+  ClutterActorMeta *meta;
+
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+  g_return_if_fail (name != NULL);
+
+  priv = self->priv;
+
+  if (priv->effects == NULL)
+    return;
+
+  meta = _clutter_meta_group_get_meta (priv->effects, name);
+  if (meta == NULL)
+    return;
+
+  _clutter_meta_group_remove_meta (priv->effects, meta);
+}
+
+/**
+ * clutter_actor_get_effects:
+ * @self: a #ClutterActor
+ *
+ * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
+ *
+ * Return value: (transfer container) (element-type ClutterEffect): a list
+ *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
+ *   list are owned by Clutter and they should not be freed. You should
+ *   free the returned list using g_list_free() when done
+ *
+ * Since: 1.4
+ */
+GList *
+clutter_actor_get_effects (ClutterActor *self)
+{
+  ClutterActorPrivate *priv;
+  const GList *effects;
+
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
+
+  priv = self->priv;
+
+  if (priv->effects == NULL)
+    return NULL;
+
+  effects = _clutter_meta_group_peek_metas (priv->effects);
+
+  return g_list_copy ((GList *) effects);
+}
+
+/**
+ * clutter_actor_get_effect:
+ * @self: a #ClutterActor
+ * @name: the name of the effect to retrieve
+ *
+ * Retrieves the #ClutterEffect with the given name in the list
+ * of effects applied to @self
+ *
+ * Return value: (transfer none): a #ClutterEffect for the given
+ *   name, or %NULL. The returned #ClutterEffect is owned by the
+ *   actor and it should not be unreferenced directly
+ *
+ * Since: 1.4
+ */
+ClutterEffect *
+clutter_actor_get_effect (ClutterActor *self,
+                          const gchar  *name)
+{
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+
+  if (self->priv->effects == NULL)
+    return NULL;
+
+  return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
+}
+
+/**
+ * clutter_actor_clear_effects:
+ * @self: a #ClutterActor
+ *
+ * Clears the list of effects applied to @self
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_clear_effects (ClutterActor *self)
+{
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+  if (self->priv->effects == NULL)
+    return;
+
+  _clutter_meta_group_clear_metas (self->priv->effects);
+}
index 2ca9ff3..ff2c96d 100644 (file)
 
 /* clutter-actor.h */
 
-#include <glib-object.h>
 #include <pango/pango.h>
 #include <atk/atk.h>
 
-#include <clutter/clutter-color.h>
 #include <clutter/clutter-types.h>
+
+#include <clutter/clutter-color.h>
+#include <clutter/clutter-effect.h>
 #include <clutter/clutter-event.h>
 #include <clutter/clutter-shader.h>
 
diff --git a/clutter/clutter-effect.c b/clutter/clutter-effect.c
new file mode 100644 (file)
index 0000000..6c79458
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Emmanuele Bassi <ebassi@linux.intel.com>
+ */
+
+/**
+ * SECTION:clutter-effect
+ * @short_description: Base class for actor effects
+ *
+ * The #ClutterEffect class provides a default type and API for creating
+ * effects for generic actors.
+ *
+ * Effects are a #ClutterActorMeta sub-class that modify the way an actor
+ * is painted in a way that is not part of the actor's implementation.
+ *
+ * Effects should be the preferred way to affect the paint sequence of an
+ * actor without sub-classing the actor itself and overriding the
+ * #ClutterActor::paint virtual function.
+ *
+ * <refsect2 id="ClutterEffect-implementation">
+ *   <title>Implementing a ClutterEffect</title>
+ *   <para>Creating a sub-class of #ClutterEffect requires the implementation
+ *   of three virtual functions:</para>
+ *   <itemizedlist>
+ *     <listitem><simpara><function>prepare()</function>, which is called when
+ *     attaching the #ClutterEffect to a #ClutterActor through the
+ *     clutter_actor_set_effect() function or when the actor is being
+ *     painted;</simpara></listitem>
+ *     <listitem><simpara><function>pre_paint()</function>, which is called
+ *     before painting the #ClutterActor.</simpara></listitem>
+ *     <listitem><simpara><function>post_paint()</function>, which is called
+ *     after painting the #ClutterActor.</simpara></listitem>
+ *   </itemizedlist>
+ *   <para>The <function>prepare()</function> 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.</para>
+ *   <para>The <function>pre_paint()</function> function should be used to set
+ *   up the #ClutterEffect right before the #ClutterActor's paint
+ *   sequence. This function, like <function>prepare()</function> can fail, and
+ *   return %FALSE; in that case, no <function>post_paint()</function>
+ *   invocation will follow.</para>
+ *   <para>The <function>post_paint()</function> function is called after the
+ *   #ClutterActor's paint sequence.</para>
+ *   <para>The <function>pre_paint()</function> phase could be seen as a custom
+ *   handler to the #ClutterActor::paint signal, while the
+ *   <function>post_paint()</function> phase could be seen as a custom handler
+ *   to the #ClutterActor::paint signal connected using
+ *   g_signal_connect_after().</para>
+ *   <example id="ClutterEffect-example">
+ *     <title>A simple ClutterEffect implementation</title>
+ *     <para>The example below creates two rectangles: one will be painted
+ *     "behind" the actor, while another will be painted "on top" of the actor.
+ *     The <function>prepare()</function> phase will create the two materials
+ *     used for the two different rectangles; the
+ *     <function>pre_paint()</function> function will paint the first material
+ *     using cogl_rectangle(), while the <function>post_paint()</function>
+ *     phase will paint the second material.</para>
+ *     <programlisting>
+ *  typedef struct {
+ *    ClutterEffect parent_instance;
+ *
+ *    CoglHandle rect_1;
+ *    CoglHandle rect_2;
+ *  } MyEffect;
+ *
+ *  typedef struct _ClutterEffectClass MyEffectClass;
+ *
+ *  G_DEFINE_TYPE (MyEffect, my_effect, CLUTTER_TYPE_EFFECT);
+ *
+ *  static void
+ *  my_effect_set_actor (ClutterActorMeta *meta,
+ *                       ClutterActor     *actor)
+ *  {
+ *    MyEffect *self = MY_EFFECT (meta);
+ *
+ *    /&ast; Clear the previous state &ast;/
+ *    if (self-&gt;rect_1)
+ *      {
+ *        cogl_handle_unref (self-&gt;rect_1);
+ *        self-&gt;rect_1 = NULL;
+ *      }
+ *
+ *    if (self-&gt;rect_2)
+ *      {
+ *        cogl_handle_unref (self-&gt;rect_2);
+ *        self-&gt;rect_2 = NULL;
+ *      }
+ *
+ *    /&ast; Maintain a pointer to the actor &ast;
+ *    self-&gt;actor = actor;
+ *
+ *    /&ast; If we've been detached by the actor then we should
+ *     &ast; just bail out here
+ *     &ast;/
+ *    if (self-&gt;actor == NULL)
+ *      return;
+ *
+ *    /&ast; Create a red material &ast;/
+ *    self-&gt;rect_1 = cogl_material_new ();
+ *    cogl_material_set_color4f (self-&gt;rect_1, 1.0, 0.0, 0.0, 1.0);
+ *
+ *    /&ast; Create a green material &ast;/
+ *    self-&gt;rect_2 = cogl_material_new ();
+ *    cogl_material_set_color4f (self-&gt;rect_2, 0.0, 1.0, 0.0, 1.0);
+ *  }
+ *
+ *  static gboolean
+ *  my_effect_pre_paint (ClutterEffect *effect)
+ *  {
+ *    MyEffect *self = MY_EFFECT (effect);
+ *    gfloat width, height;
+ *
+ *    /&ast; If we were disabled we don't need to paint anything &ast;/
+ *    if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
+ *      return FALSE;
+ *
+ *    clutter_actor_get_size (self-&gt;actor, &amp;width, &amp;height);
+ *
+ *    /&ast; Paint the first rectangle in the upper left quadrant &ast;/
+ *    cogl_set_source (self-&gt;rect_1);
+ *    cogl_rectangle (0, 0, width / 2, height / 2);
+ *
+ *    return TRUE;
+ *  }
+ *
+ *  static void
+ *  my_effect_post_paint (ClutterEffect *effect)
+ *  {
+ *    MyEffect *self = MY_EFFECT (effect);
+ *    gfloat width, height;
+ *
+ *    clutter_actor_get_size (self-&gt;actor, &amp;width, &amp;height);
+ *
+ *    /&ast; Paint the second rectangle in the lower right quadrant &ast;/
+ *    cogl_set_source (self-&gt;rect_2);
+ *    cogl_rectangle (width / 2, height / 2, width, height);
+ *  }
+ *
+ *  static void
+ *  my_effect_class_init (MyEffectClass *klass)
+ *  {
+ *    ClutterActorMetaClas *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
+ *
+ *    meta_class-&gt;set_actor = my_effect_set_actor;
+ *
+ *    klass-&gt;pre_paint = my_effect_pre_paint;
+ *    klass-&gt;post_paint = my_effect_post_paint;
+ *  }
+ *     </programlisting>
+ *   </example>
+ * </refsect2>
+ *
+ * #ClutterEffect is available since Clutter 1.4
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter-effect.h"
+
+#include "clutter-actor-meta-private.h"
+#include "clutter-debug.h"
+#include "clutter-enum-types.h"
+#include "clutter-marshal.h"
+#include "clutter-private.h"
+
+G_DEFINE_ABSTRACT_TYPE (ClutterEffect,
+                        clutter_effect,
+                        CLUTTER_TYPE_ACTOR_META);
+
+static gboolean
+clutter_effect_real_pre_paint (ClutterEffect *effect)
+{
+  return TRUE;
+}
+
+static void
+clutter_effect_real_post_paint (ClutterEffect *effect)
+{
+}
+
+static void
+clutter_effect_class_init (ClutterEffectClass *klass)
+{
+  klass->pre_paint = clutter_effect_real_pre_paint;
+  klass->post_paint = clutter_effect_real_post_paint;
+}
+
+static void
+clutter_effect_init (ClutterEffect *self)
+{
+}
+
+gboolean
+_clutter_effect_pre_paint (ClutterEffect *effect)
+{
+  g_return_val_if_fail (CLUTTER_IS_EFFECT (effect), FALSE);
+
+  return CLUTTER_EFFECT_GET_CLASS (effect)->pre_paint (effect);
+}
+
+void
+_clutter_effect_post_paint (ClutterEffect *effect)
+{
+  g_return_if_fail (CLUTTER_IS_EFFECT (effect));
+
+  CLUTTER_EFFECT_GET_CLASS (effect)->post_paint (effect);
+}
diff --git a/clutter/clutter-effect.h b/clutter/clutter-effect.h
new file mode 100644 (file)
index 0000000..8b45f16
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Emmanuele Bassi <ebassi@linux.intel.com>
+ */
+
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only <clutter/clutter.h> can be included directly."
+#endif
+
+#ifndef __CLUTTER_EFFECT_H__
+#define __CLUTTER_EFFECT_H__
+
+#include <clutter/clutter-actor-meta.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_EFFECT             (clutter_effect_get_type ())
+#define CLUTTER_EFFECT(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_EFFECT, ClutterEffect))
+#define CLUTTER_IS_EFFECT(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_EFFECT))
+#define CLUTTER_EFFECT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_EFFECT, ClutterEffectClass))
+#define CLUTTER_IS_EFFECT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_EFFECT))
+#define CLUTTER_EFFECT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_EFFECT, ClutterEffectClass))
+
+typedef struct _ClutterEffect           ClutterEffect;
+typedef struct _ClutterEffectClass      ClutterEffectClass;
+
+/**
+ * ClutterEffect:
+ *
+ * The #ClutterEffect structure contains only private data and should
+ * be accessed using the provided API
+ *
+ * Since: 1.4
+ */
+struct _ClutterEffect
+{
+  /*< private >*/
+  ClutterActorMeta parent_instance;
+};
+
+/**
+ * ClutterEffectClass:
+ * @prepare: virtual function
+ * @pre_paint: virtual function
+ * @post_paint: virtual function
+ *
+ * The #ClutterEffectClass structure contains only private data
+ *
+ * Since: 1.4
+ */
+struct _ClutterEffectClass
+{
+  /*< private >*/
+  ClutterActorMetaClass parent_class;
+
+  /*< public >*/
+  gboolean (* pre_paint)  (ClutterEffect *effect);
+  void     (* post_paint) (ClutterEffect *effect);
+
+  /*< private >*/
+  void (* _clutter_effect1) (void);
+  void (* _clutter_effect2) (void);
+  void (* _clutter_effect3) (void);
+  void (* _clutter_effect4) (void);
+  void (* _clutter_effect5) (void);
+  void (* _clutter_effect6) (void);
+};
+
+GType clutter_effect_get_type (void) G_GNUC_CONST;
+
+/*
+ * ClutterActor API
+ */
+
+void           clutter_actor_add_effect            (ClutterActor  *self,
+                                                    ClutterEffect *effect);
+void           clutter_actor_add_effect_with_name  (ClutterActor  *self,
+                                                    const gchar   *name,
+                                                    ClutterEffect *effect);
+void           clutter_actor_remove_effect         (ClutterActor  *self,
+                                                    ClutterEffect *effect);
+void           clutter_actor_remove_effect_by_name (ClutterActor  *self,
+                                                    const gchar   *name);
+GList *        clutter_actor_get_effects           (ClutterActor  *self);
+ClutterEffect *clutter_actor_get_effect            (ClutterActor  *self,
+                                                    const gchar   *name);
+void           clutter_actor_clear_effects         (ClutterActor  *self);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_EFFECT_H__ */
index bf06563..88a29a9 100644 (file)
@@ -38,6 +38,7 @@
 
 #include "clutter-backend.h"
 #include "clutter-device-manager.h"
+#include "clutter-effect.h"
 #include "clutter-event.h"
 #include "clutter-feature.h"
 #include "clutter-id-pool.h"
@@ -331,6 +332,9 @@ void _clutter_run_repaint_functions (void);
 
 gint32 _clutter_backend_get_units_serial (ClutterBackend *backend);
 
+gboolean _clutter_effect_pre_paint  (ClutterEffect *effect);
+void     _clutter_effect_post_paint (ClutterEffect *effect);
+
 G_END_DECLS
 
 #endif /* _HAVE_CLUTTER_PRIVATE_H */
index 0e7c2d7..a9dc992 100644 (file)
@@ -60,6 +60,7 @@
 #include "clutter-container.h"
 #include "clutter-device-manager.h"
 #include "clutter-drag-action.h"
+#include "clutter-effect.h"
 #include "clutter-event.h"
 #include "clutter-feature.h"
 #include "clutter-fixed-layout.h"
index e6174a5..2001090 100644 (file)
@@ -44,8 +44,8 @@ test_rotate_main (int argc, char *argv[])
   clutter_text_set_line_alignment (CLUTTER_TEXT (label), PANGO_ALIGN_CENTER);
   clutter_actor_set_position (label, 150, 150);
   clutter_actor_set_size (label, 500, 100);
-  clutter_actor_show (label);
-  clutter_container_add_actor (CLUTTER_CONTAINER (stage), label);
+
+  clutter_container_add (CLUTTER_CONTAINER (stage), hand, label, NULL);
   
   /* Make a timeline */
   timeline = clutter_timeline_new (7692); /* num frames, fps */