/* * 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 */ /** * 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. * * * Implementing a ClutterEffect * Creating a sub-class of #ClutterEffect requires the implementation * of two virtual functions: * * pre_paint(), which is called * before painting the #ClutterActor. * post_paint(), which is called * after painting the #ClutterActor. * * The pre_paint() 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 * 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 * handler to the #ClutterActor::paint signal, while the * post_paint() phase could be seen as a custom handler * to the #ClutterActor::paint signal connected using * g_signal_connect_after(). * * 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 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. * * 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; * } * * * * * #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_class_init (ClutterEffectClass *klass) { 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); }