Release Clutter 1.11.4 (snapshot)
[profile/ivi/clutter.git] / clutter / clutter-effect.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Copyright (C) 2010  Intel Corporation.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20  *
21  * Author:
22  *   Emmanuele Bassi <ebassi@linux.intel.com>
23  */
24
25 /**
26  * SECTION:clutter-effect
27  * @short_description: Base class for actor effects
28  *
29  * The #ClutterEffect class provides a default type and API for creating
30  * effects for generic actors.
31  *
32  * Effects are a #ClutterActorMeta sub-class that modify the way an actor
33  * is painted in a way that is not part of the actor's implementation.
34  *
35  * Effects should be the preferred way to affect the paint sequence of an
36  * actor without sub-classing the actor itself and overriding the
37  * #ClutterActorClass.paint()_ virtual function.
38  *
39  * <refsect2 id="ClutterEffect-implementation">
40  *   <title>Implementing a ClutterEffect</title>
41  *   <para>
42  *     Creating a sub-class of #ClutterEffect requires overriding the
43  *     ‘paint’ method. The implementation of the function should look
44  *     something like this:
45  *   </para>
46  *   <programlisting>
47  * void effect_paint (ClutterEffect *effect, ClutterEffectPaintFlags flags)
48  * {
49  *   /&ast; Set up initialisation of the paint such as binding a
50  *      CoglOffscreen or other operations &ast;/
51  *
52  *   /&ast; Chain to the next item in the paint sequence. This will either call
53  *      ‘paint’ on the next effect or just paint the actor if this is
54  *      the last effect. &ast;/
55  *   ClutterActor *actor =
56  *     clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
57  *   clutter_actor_continue_paint (actor);
58  *
59  *   /&ast; perform any cleanup of state, such as popping the
60  *      CoglOffscreen &ast;/
61  * }
62  *   </programlisting>
63  *   <para>
64  *     The effect can optionally avoid calling
65  *     clutter_actor_continue_paint() to skip any further stages of
66  *     the paint sequence. This is useful for example if the effect
67  *     contains a cached image of the actor. In that case it can
68  *     optimise painting by avoiding the actor paint and instead
69  *     painting the cached image. The %CLUTTER_EFFECT_PAINT_ACTOR_DIRTY
70  *     flag is useful in this case. Clutter will set this flag when a
71  *     redraw has been queued on the actor since it was last
72  *     painted. The effect can use this information to decide if the
73  *     cached image is still valid.
74  *   </para>
75  *   <para>
76  *     The ‘paint’ virtual was added in Clutter 1.8. Prior to that there
77  *     were two separate functions as follows.
78  *   </para>
79  *   <itemizedlist>
80  *     <listitem><simpara><function>pre_paint()</function>, which is called
81  *     before painting the #ClutterActor.</simpara></listitem>
82  *     <listitem><simpara><function>post_paint()</function>, which is called
83  *     after painting the #ClutterActor.</simpara></listitem>
84  *   </itemizedlist>
85  *   <para>The <function>pre_paint()</function> function was used to set
86  *   up the #ClutterEffect right before the #ClutterActor's paint
87  *   sequence. This function can fail, and return %FALSE; in that case, no
88  *   <function>post_paint()</function> invocation will follow.</para>
89  *   <para>The <function>post_paint()</function> function was called after the
90  *   #ClutterActor's paint sequence.</para>
91  *   <para>
92  *     With these two functions it is not possible to skip the rest of
93  *     the paint sequence. The default implementation of the ‘paint’
94  *     virtual calls #ClutterEffectClass.pre_paint(), clutter_actor_continue_paint()
95  *     and then #ClutterEffectClass.post_paint() so that existing actors that aren't
96  *     using the #ClutterEffectClass.paint() virtual will continue to work. New
97  *     effects using the #ClutterEffectClass.paint() virtual do not need to implement
98  *     pre or post paint.
99  *   </para>
100  *   <example id="ClutterEffect-example">
101  *     <title>A simple ClutterEffect implementation</title>
102  *     <para>The example below creates two rectangles: one will be
103  *     painted "behind" the actor, while another will be painted "on
104  *     top" of the actor.  The #ClutterActorMetaClass.set_actor()
105  *     implementation will create the two materials used for the two
106  *     different rectangles; the #ClutterEffectClass.paint() implementation
107  *     will paint the first material using cogl_rectangle(), before
108  *     continuing and then it will paint paint the second material
109  *     after.</para>
110  *     <programlisting>
111  *  typedef struct {
112  *    ClutterEffect parent_instance;
113  *
114  *    CoglHandle rect_1;
115  *    CoglHandle rect_2;
116  *  } MyEffect;
117  *
118  *  typedef struct _ClutterEffectClass MyEffectClass;
119  *
120  *  G_DEFINE_TYPE (MyEffect, my_effect, CLUTTER_TYPE_EFFECT);
121  *
122  *  static void
123  *  my_effect_set_actor (ClutterActorMeta *meta,
124  *                       ClutterActor     *actor)
125  *  {
126  *    MyEffect *self = MY_EFFECT (meta);
127  *
128  *    /&ast; Clear the previous state &ast;/
129  *    if (self-&gt;rect_1)
130  *      {
131  *        cogl_handle_unref (self-&gt;rect_1);
132  *        self-&gt;rect_1 = NULL;
133  *      }
134  *
135  *    if (self-&gt;rect_2)
136  *      {
137  *        cogl_handle_unref (self-&gt;rect_2);
138  *        self-&gt;rect_2 = NULL;
139  *      }
140  *
141  *    /&ast; Maintain a pointer to the actor &ast;
142  *    self-&gt;actor = actor;
143  *
144  *    /&ast; If we've been detached by the actor then we should
145  *     &ast; just bail out here
146  *     &ast;/
147  *    if (self-&gt;actor == NULL)
148  *      return;
149  *
150  *    /&ast; Create a red material &ast;/
151  *    self-&gt;rect_1 = cogl_material_new ();
152  *    cogl_material_set_color4f (self-&gt;rect_1, 1.0, 0.0, 0.0, 1.0);
153  *
154  *    /&ast; Create a green material &ast;/
155  *    self-&gt;rect_2 = cogl_material_new ();
156  *    cogl_material_set_color4f (self-&gt;rect_2, 0.0, 1.0, 0.0, 1.0);
157  *  }
158  *
159  *  static gboolean
160  *  my_effect_paint (ClutterEffect *effect)
161  *  {
162  *    MyEffect *self = MY_EFFECT (effect);
163  *    gfloat width, height;
164  *
165  *    clutter_actor_get_size (self-&gt;actor, &amp;width, &amp;height);
166  *
167  *    /&ast; Paint the first rectangle in the upper left quadrant &ast;/
168  *    cogl_set_source (self-&gt;rect_1);
169  *    cogl_rectangle (0, 0, width / 2, height / 2);
170  *
171  *    /&ast; Continue to the rest of the paint sequence &ast;/
172  *    clutter_actor_continue_paint (self-&gt;actor);
173  *
174  *    /&ast; Paint the second rectangle in the lower right quadrant &ast;/
175  *    cogl_set_source (self-&gt;rect_2);
176  *    cogl_rectangle (width / 2, height / 2, width, height);
177  *  }
178  *
179  *  static void
180  *  my_effect_class_init (MyEffectClass *klass)
181  *  {
182  *    ClutterActorMetaClas *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
183  *
184  *    meta_class-&gt;set_actor = my_effect_set_actor;
185  *
186  *    klass-&gt;paint = my_effect_paint;
187  *  }
188  *     </programlisting>
189  *   </example>
190  * </refsect2>
191  *
192  * #ClutterEffect is available since Clutter 1.4
193  */
194
195 #ifdef HAVE_CONFIG_H
196 #include "config.h"
197 #endif
198
199 #include "clutter-effect.h"
200
201 #include "clutter-actor-meta-private.h"
202 #include "clutter-debug.h"
203 #include "clutter-effect-private.h"
204 #include "clutter-enum-types.h"
205 #include "clutter-marshal.h"
206 #include "clutter-private.h"
207 #include "clutter-actor-private.h"
208
209 G_DEFINE_ABSTRACT_TYPE (ClutterEffect,
210                         clutter_effect,
211                         CLUTTER_TYPE_ACTOR_META);
212
213 static gboolean
214 clutter_effect_real_pre_paint (ClutterEffect *effect)
215 {
216   return TRUE;
217 }
218
219 static void
220 clutter_effect_real_post_paint (ClutterEffect *effect)
221 {
222 }
223
224 static gboolean
225 clutter_effect_real_get_paint_volume (ClutterEffect      *effect,
226                                       ClutterPaintVolume *volume)
227 {
228   return TRUE;
229 }
230
231 static void
232 clutter_effect_real_paint (ClutterEffect           *effect,
233                            ClutterEffectPaintFlags  flags)
234 {
235   ClutterActorMeta *actor_meta = CLUTTER_ACTOR_META (effect);
236   ClutterActor *actor;
237   gboolean pre_paint_succeeded;
238
239   /* The default implementation provides a compatibility wrapper for
240      effects that haven't migrated to use the 'paint' virtual yet. This
241      just calls the old pre and post virtuals before chaining on */
242
243   pre_paint_succeeded = _clutter_effect_pre_paint (effect);
244
245   actor = clutter_actor_meta_get_actor (actor_meta);
246   clutter_actor_continue_paint (actor);
247
248   if (pre_paint_succeeded)
249     _clutter_effect_post_paint (effect);
250 }
251
252 static void
253 clutter_effect_real_pick (ClutterEffect           *effect,
254                           ClutterEffectPaintFlags  flags)
255 {
256   ClutterActorMeta *actor_meta = CLUTTER_ACTOR_META (effect);
257   ClutterActor *actor;
258
259   actor = clutter_actor_meta_get_actor (actor_meta);
260   clutter_actor_continue_paint (actor);
261 }
262
263 static void
264 clutter_effect_notify (GObject    *gobject,
265                        GParamSpec *pspec)
266 {
267   if (strcmp (pspec->name, "enabled") == 0)
268     {
269       ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
270       ClutterActor *actor = clutter_actor_meta_get_actor (meta);
271
272       if (actor != NULL)
273         clutter_actor_queue_redraw (actor);
274     }
275
276   if (G_OBJECT_CLASS (clutter_effect_parent_class)->notify != NULL)
277     G_OBJECT_CLASS (clutter_effect_parent_class)->notify (gobject, pspec);
278 }
279
280 static void
281 clutter_effect_class_init (ClutterEffectClass *klass)
282 {
283   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
284
285   gobject_class->notify = clutter_effect_notify;
286
287   klass->pre_paint = clutter_effect_real_pre_paint;
288   klass->post_paint = clutter_effect_real_post_paint;
289   klass->get_paint_volume = clutter_effect_real_get_paint_volume;
290   klass->paint = clutter_effect_real_paint;
291   klass->pick = clutter_effect_real_pick;
292 }
293
294 static void
295 clutter_effect_init (ClutterEffect *self)
296 {
297 }
298
299 gboolean
300 _clutter_effect_pre_paint (ClutterEffect *effect)
301 {
302   g_return_val_if_fail (CLUTTER_IS_EFFECT (effect), FALSE);
303
304   return CLUTTER_EFFECT_GET_CLASS (effect)->pre_paint (effect);
305 }
306
307 void
308 _clutter_effect_post_paint (ClutterEffect *effect)
309 {
310   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
311
312   CLUTTER_EFFECT_GET_CLASS (effect)->post_paint (effect);
313 }
314
315 void
316 _clutter_effect_paint (ClutterEffect           *effect,
317                        ClutterEffectPaintFlags  flags)
318 {
319   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
320
321   CLUTTER_EFFECT_GET_CLASS (effect)->paint (effect, flags);
322 }
323
324 void
325 _clutter_effect_pick (ClutterEffect           *effect,
326                       ClutterEffectPaintFlags  flags)
327 {
328   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
329
330   CLUTTER_EFFECT_GET_CLASS (effect)->pick (effect, flags);
331 }
332
333 gboolean
334 _clutter_effect_get_paint_volume (ClutterEffect      *effect,
335                                   ClutterPaintVolume *volume)
336 {
337   g_return_val_if_fail (CLUTTER_IS_EFFECT (effect), FALSE);
338   g_return_val_if_fail (volume != NULL, FALSE);
339
340   return CLUTTER_EFFECT_GET_CLASS (effect)->get_paint_volume (effect, volume);
341 }
342
343 /**
344  * clutter_effect_queue_repaint:
345  * @effect: A #ClutterEffect which needs redrawing
346  *
347  * Queues a repaint of the effect. The effect can detect when the ‘paint’
348  * method is called as a result of this function because it will not
349  * have the %CLUTTER_EFFECT_PAINT_ACTOR_DIRTY flag set. In that case the
350  * effect is free to assume that the actor has not changed its
351  * appearance since the last time it was painted so it doesn't need to
352  * call clutter_actor_continue_paint() if it can draw a cached
353  * image. This is mostly intended for effects that are using a
354  * %CoglOffscreen to redirect the actor (such as
355  * %ClutterOffscreenEffect). In that case the effect can save a bit of
356  * rendering time by painting the cached texture without causing the
357  * entire actor to be painted.
358  *
359  * This function can be used by effects that have their own animatable
360  * parameters. For example, an effect which adds a varying degree of a
361  * red tint to an actor by redirecting it through a CoglOffscreen
362  * might have a property to specify the level of tint. When this value
363  * changes, the underlying actor doesn't need to be redrawn so the
364  * effect can call clutter_effect_queue_repaint() to make sure the
365  * effect is repainted.
366  *
367  * Note however that modifying the position of the parent of an actor
368  * may change the appearance of the actor because its transformation
369  * matrix would change. In this case a redraw wouldn't be queued on
370  * the actor itself so the %CLUTTER_EFFECT_PAINT_ACTOR_DIRTY would still
371  * not be set. The effect can detect this case by keeping track of the
372  * last modelview matrix that was used to render the actor and
373  * veryifying that it remains the same in the next paint.
374  *
375  * Any other effects that are layered on top of the passed in effect
376  * will still be passed the %CLUTTER_EFFECT_PAINT_ACTOR_DIRTY flag. If
377  * anything queues a redraw on the actor without specifying an effect
378  * or with an effect that is lower in the chain of effects than this
379  * one then that will override this call. In that case this effect
380  * will instead be called with the %CLUTTER_EFFECT_PAINT_ACTOR_DIRTY
381  * flag set.
382  *
383  * Since: 1.8
384  */
385 void
386 clutter_effect_queue_repaint (ClutterEffect *effect)
387 {
388   ClutterActor *actor;
389
390   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
391
392   actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
393
394   /* If the effect has no actor then nothing needs to be done */
395   if (actor != NULL)
396     _clutter_actor_queue_redraw_full (actor,
397                                       0, /* flags */
398                                       NULL, /* clip volume */
399                                       effect /* effect */);
400 }