3540d222e1
This is a fairly extensive second pass at exposing paint volumes for actors. The API has changed to allow clutter_actor_get_paint_volume to fail since there are times - such as when an actor isn't a descendent of the stage - when the volume can't be determined. Another example is when something has connected to the "paint" signal of the actor and we simply have no way of knowing what might be drawn in that handler. The API has also be changed to return a const ClutterPaintVolume pointer (transfer none) so we can avoid having to dynamically allocate the volumes in the most common/performance critical code paths. Profiling was showing the slice allocation of volumes taking about 1% of an apps time, for some fairly basic tests. Most volumes can now simply be allocated on the stack; for clutter_actor_get_paint_volume we return a pointer to &priv->paint_volume and if we need a more dynamic allocation there is now a _clutter_stage_paint_volume_stack_allocate() mechanism which lets us allocate data which expires at the start of the next frame. The API has been extended to make it easier to implement get_paint_volume for containers by using clutter_actor_get_transformed_paint_volume and clutter_paint_volume_union. The first allows you to query the paint volume of a child but transformed into parent actor coordinates. The second lets you combine volumes together so you can union all the volumes for a container's children and report that as the container's own volume. The representation of paint volumes has been updated to consider that 2D actors are the most common. The effect apis, clutter-texture and clutter-group have been update accordingly.
239 lines
7.5 KiB
C
239 lines
7.5 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-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);
|
|
}
|