0be73bf401
ClutterEffect should queue a redraw if the :enabled property of its parent class ClutterActorMeta changes. http://bugzilla.clutter-project.org/show_bug.cgi?id=2587
261 lines
8.1 KiB
C
261 lines
8.1 KiB
C
/*
|
|
* 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 two virtual functions:</para>
|
|
* <itemizedlist>
|
|
* <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>pre_paint()</function> function should be used to set
|
|
* up the #ClutterEffect right before the #ClutterActor's paint
|
|
* sequence. This 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>set_actor()</function> implementation 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);
|
|
*
|
|
* /* Clear the previous state */
|
|
* if (self->rect_1)
|
|
* {
|
|
* cogl_handle_unref (self->rect_1);
|
|
* self->rect_1 = NULL;
|
|
* }
|
|
*
|
|
* if (self->rect_2)
|
|
* {
|
|
* cogl_handle_unref (self->rect_2);
|
|
* self->rect_2 = NULL;
|
|
* }
|
|
*
|
|
* /* Maintain a pointer to the actor *
|
|
* self->actor = actor;
|
|
*
|
|
* /* If we've been detached by the actor then we should
|
|
* * just bail out here
|
|
* */
|
|
* if (self->actor == NULL)
|
|
* return;
|
|
*
|
|
* /* Create a red material */
|
|
* self->rect_1 = cogl_material_new ();
|
|
* cogl_material_set_color4f (self->rect_1, 1.0, 0.0, 0.0, 1.0);
|
|
*
|
|
* /* Create a green material */
|
|
* self->rect_2 = cogl_material_new ();
|
|
* cogl_material_set_color4f (self->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;
|
|
*
|
|
* /* If we were disabled we don't need to paint anything */
|
|
* if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
|
|
* return FALSE;
|
|
*
|
|
* clutter_actor_get_size (self->actor, &width, &height);
|
|
*
|
|
* /* Paint the first rectangle in the upper left quadrant */
|
|
* cogl_set_source (self->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->actor, &width, &height);
|
|
*
|
|
* /* Paint the second rectangle in the lower right quadrant */
|
|
* cogl_set_source (self->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->set_actor = my_effect_set_actor;
|
|
*
|
|
* klass->pre_paint = my_effect_pre_paint;
|
|
* klass->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-effect-private.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 gboolean
|
|
clutter_effect_real_get_paint_volume (ClutterEffect *effect,
|
|
ClutterPaintVolume *volume)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
clutter_effect_notify (GObject *gobject,
|
|
GParamSpec *pspec)
|
|
{
|
|
if (strcmp (pspec->name, "enabled") == 0)
|
|
{
|
|
ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
|
|
ClutterActor *actor = clutter_actor_meta_get_actor (meta);
|
|
|
|
if (actor != NULL)
|
|
clutter_actor_queue_redraw (actor);
|
|
}
|
|
|
|
if (G_OBJECT_CLASS (clutter_effect_parent_class)->notify != NULL)
|
|
G_OBJECT_CLASS (clutter_effect_parent_class)->notify (gobject, pspec);
|
|
}
|
|
|
|
static void
|
|
clutter_effect_class_init (ClutterEffectClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->notify = clutter_effect_notify;
|
|
|
|
klass->pre_paint = clutter_effect_real_pre_paint;
|
|
klass->post_paint = clutter_effect_real_post_paint;
|
|
klass->get_paint_volume = clutter_effect_real_get_paint_volume;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
gboolean
|
|
_clutter_effect_get_paint_volume (ClutterEffect *effect,
|
|
ClutterPaintVolume *volume)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_EFFECT (effect), FALSE);
|
|
g_return_val_if_fail (volume != NULL, FALSE);
|
|
|
|
return CLUTTER_EFFECT_GET_CLASS (effect)->get_paint_volume (effect, volume);
|
|
}
|