770 lines
29 KiB
XML
770 lines
29 KiB
XML
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||
|
|
||
|
<chapter id="effects" xmlns:xi="http://www.w3.org/2003/XInclude">
|
||
|
<title>Effects</title>
|
||
|
|
||
|
<epigraph>
|
||
|
<attribution>Roger Zelazny, from <citetitle>Prince of Chaos</citetitle>
|
||
|
</attribution>
|
||
|
<para>Don't wake me for the end of the world unless it has very
|
||
|
good special effects</para>
|
||
|
</epigraph>
|
||
|
|
||
|
<section id="effects-introduction">
|
||
|
<title>Introduction</title>
|
||
|
|
||
|
<para>Effects modify an actor's appearance, such
|
||
|
as how it is positioned, colored and textured.</para>
|
||
|
|
||
|
<para>The Clutter API for effects contains several
|
||
|
abstract classes you can subclass to create your own effects.
|
||
|
It also contains several built-in effects you can use to
|
||
|
modify the visual appearance of actors in a variety of ways.</para>
|
||
|
|
||
|
<para>The recipes in this section of the cookbook cover how to create
|
||
|
your own effects as well as how to apply Clutter's effects.</para>
|
||
|
|
||
|
<section>
|
||
|
<title>Creating effects using the abstract effect classes</title>
|
||
|
|
||
|
<tip>
|
||
|
<para>One of the original design goals of Clutter was to abstract
|
||
|
the complexity of GL. However, the effects API partially circumvents
|
||
|
these abstractions, to give you finer-grained access to the
|
||
|
graphics pipeline. Therefore, if you want to write your own effects,
|
||
|
some understanding of Cogl, OpenGL, and general graphics programming
|
||
|
is essential.</para>
|
||
|
</tip>
|
||
|
|
||
|
<para>Each abstract effect class is tailored to modifying different
|
||
|
aspects of an actor, as explained below:</para>
|
||
|
|
||
|
<itemizedlist>
|
||
|
|
||
|
<listitem>
|
||
|
<formalpara>
|
||
|
<title><type>ClutterEffect</type></title>
|
||
|
<para>If you're just using the Clutter and Cogl APIs to
|
||
|
decorate an actor, this is simplest type of effect to
|
||
|
implement.</para>
|
||
|
</formalpara>
|
||
|
|
||
|
<para>Subclassing <type>ClutterEffect</type> enables you to
|
||
|
"wrap" how an actor is painted, by injecting some code before
|
||
|
and/or after the actor's own <function>paint()</function>
|
||
|
implementation.</para>
|
||
|
|
||
|
<note>
|
||
|
<para>This is the preferred way to modify how an actor is
|
||
|
painted, short of creating your own actor subclass.</para>
|
||
|
</note>
|
||
|
|
||
|
<para><emphasis>Subclasses of
|
||
|
<type>ClutterEffect</type></emphasis>:</para>
|
||
|
|
||
|
<itemizedlist>
|
||
|
|
||
|
<listitem>
|
||
|
<formalpara>
|
||
|
<title><type>ClutterOffscreenEffect</type></title>
|
||
|
|
||
|
<para>Use this class as a basis if you need GL textures
|
||
|
for your effect.</para>
|
||
|
</formalpara>
|
||
|
|
||
|
<para>GL textures are required for effects which need
|
||
|
an offscreen framebuffer. The offscreen framebuffer is
|
||
|
used to store a modified rendering of an actor (e.g.
|
||
|
with its colors altered or with deformed geometry).
|
||
|
This buffer is then redirected to a texture in the
|
||
|
stage window.</para>
|
||
|
|
||
|
<para>An example is <type>ClutterBlurEffect</type>,
|
||
|
which uses a GLSL fragment shader to blur an
|
||
|
actor's appearance in an offscreen framebuffer.</para>
|
||
|
|
||
|
<para><emphasis>Subclasses of
|
||
|
<type>ClutterOffscreenEffect</type></emphasis>:</para>
|
||
|
|
||
|
<itemizedlist>
|
||
|
|
||
|
<listitem>
|
||
|
|
||
|
<formalpara>
|
||
|
<title><type>ClutterDeformEffect</type></title>
|
||
|
|
||
|
<para>Use this base class if you want to modify
|
||
|
an actor's geometry, at the level of individual
|
||
|
vertices.</para>
|
||
|
</formalpara>
|
||
|
|
||
|
<para><type>ClutterDeformEffect</type> removes the
|
||
|
complexity of dealing with vertex-based deformations
|
||
|
at the OpenGL level, instead enabling you to easily plug
|
||
|
a deformation callback into the graphics pipeline.</para>
|
||
|
|
||
|
<para>If you are writing your own deform effects,
|
||
|
a good example to work from is
|
||
|
<type>ClutterPageTurnEffect</type>.</para>
|
||
|
|
||
|
<para>There is also a
|
||
|
<link linkend="effects-custom-deform">recipe which
|
||
|
explains how to implement a simple custom deform
|
||
|
effect</link> (a page fold).</para>
|
||
|
|
||
|
</listitem>
|
||
|
|
||
|
<listitem>
|
||
|
<formalpara>
|
||
|
<title><type>ClutterShaderEffect</type></title>
|
||
|
|
||
|
<para>Use this if you want to apply custom
|
||
|
GLSL vertex or fragment shaders to your actors.</para>
|
||
|
</formalpara>
|
||
|
|
||
|
<para>Writing <type>ClutterShaderEffects</type> gives
|
||
|
you very fine-grained control over the GL pipeline.
|
||
|
However, this makes them the most complex
|
||
|
effects to implement.</para>
|
||
|
|
||
|
<tip>
|
||
|
<para>If you want to write your own GLSL shaders, the
|
||
|
<ulink url="http://www.opengl.org/documentation/glsl/">GLSL
|
||
|
specification</ulink> is a good starting point.</para>
|
||
|
</tip>
|
||
|
|
||
|
</listitem>
|
||
|
|
||
|
</itemizedlist>
|
||
|
|
||
|
</listitem>
|
||
|
|
||
|
</itemizedlist>
|
||
|
|
||
|
</listitem>
|
||
|
|
||
|
</itemizedlist>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section id="effects-introduction-using-the-built-in-effects">
|
||
|
<title>Using the built-in effects</title>
|
||
|
|
||
|
<para>Clutter comes with a number of built-in effects
|
||
|
which can easily be applied to your actors. This section
|
||
|
explains how to do this.</para>
|
||
|
|
||
|
<para>First, create an actor. For this
|
||
|
example, we use a texture loaded with an image:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
/* filename could be set from command line or constant */
|
||
|
gchar *filename;
|
||
|
|
||
|
/* create a texture */
|
||
|
ClutterActor *texture = clutter_texture_new ();
|
||
|
|
||
|
/* ...set texture size, keep aspect ratio etc... */
|
||
|
|
||
|
/* NB ignoring missing file errors here for brevity */
|
||
|
clutter_texture_set_from_file (CLUTTER_TEXTURE (texture),
|
||
|
filename,
|
||
|
NULL);
|
||
|
|
||
|
/* ...add texture to the stage... */
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>Next, create an instance of an effect; here, we're
|
||
|
creating a <type>ClutterColorizeEffect</type> with a pink tint:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
ClutterColor *pink = clutter_color_new (230, 187, 210, 255);
|
||
|
ClutterEffect *effect = clutter_colorize_effect_new (pink);
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>Finally, apply the effect to the actor:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
clutter_actor_add_effect (texture, effect);
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>The result in this case is an image colorized with
|
||
|
a pink tint, like this:</para>
|
||
|
|
||
|
<screenshot>
|
||
|
<mediaobject>
|
||
|
<imageobject>
|
||
|
<imagedata format="PNG"
|
||
|
fileref="images/effects-built-in.png" />
|
||
|
</imageobject>
|
||
|
<alt>
|
||
|
<para>Applying a <type>ClutterColorizeEffect</type>
|
||
|
to a texture loaded with an image (drawing by
|
||
|
Madeleine Smith)</para>
|
||
|
</alt>
|
||
|
</mediaobject>
|
||
|
</screenshot>
|
||
|
|
||
|
<para>The same set of steps applies for any of the built-in
|
||
|
Clutter effects. Your own custom effects classes should also
|
||
|
behave in a similar way: constructors should return
|
||
|
<type>ClutterEffect</type> instances so your effect can
|
||
|
be added to an actor through the standard API.</para>
|
||
|
|
||
|
<para>One further thing worth mentioning is that because an
|
||
|
effect is a GObject, any properties you expose for your effect
|
||
|
can be animated via implicit animations,
|
||
|
<type>ClutterAnimator</type> or <type>ClutterState</type>. For
|
||
|
example, the <type>ClutterPageTurnEffect</type> can be animated
|
||
|
by manipulating its <varname>period</varname> property. An example
|
||
|
of how to do this for your own effect is given in the
|
||
|
<link linkend="effects-custom-deform">custom deform effect
|
||
|
recipe</link>.</para>
|
||
|
|
||
|
<para>The full code for the <type>ClutterColorizeEffect</type>
|
||
|
example is below.</para>
|
||
|
|
||
|
<example id="effects-introduction-example-1">
|
||
|
<title>Applying a <type>ClutterColorizeEffect</type> to
|
||
|
a texture loaded with an image</title>
|
||
|
<programlisting>
|
||
|
<xi:include href="examples/effects-built-in.c" parse="text">
|
||
|
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
||
|
</xi:include>
|
||
|
</programlisting>
|
||
|
</example>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section id="effects-custom-deform">
|
||
|
<title>Creating and animating a custom <type>ClutterDeformEffect</type></title>
|
||
|
|
||
|
<section>
|
||
|
<title>Problem</title>
|
||
|
|
||
|
<para>You want to deform an actor's geometry: for example,
|
||
|
to make it appear stretched, twisted or folded.</para>
|
||
|
|
||
|
<para>This recipe demonstrates how to do this with a simple page
|
||
|
fold effect, which folds one half of the actor over its other half.</para>
|
||
|
</section>
|
||
|
|
||
|
<section id="effects-custom-deform-solution">
|
||
|
<title>Solution</title>
|
||
|
|
||
|
<para>Subclass <type>ClutterDeformEffect</type> and
|
||
|
implement a <function>deform_vertex()</function> function
|
||
|
to modify the actor's vertices.</para>
|
||
|
|
||
|
<para>The signature for <function>deform_vertex()</function>
|
||
|
is:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
void
|
||
|
deform_vertex (ClutterDeformEffect *effect,
|
||
|
gfloat width,
|
||
|
gfloat height,
|
||
|
CoglTextureVertex *vertex);
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>The <varname>width</varname> and <varname>height</varname>
|
||
|
are the width and height of the target material, stored in
|
||
|
the offscreen buffer. Usually the target material's size will
|
||
|
match the actor's transformed size; however, if the effect
|
||
|
implements <function>create_texture()</function>, the target
|
||
|
material's size may differ from the actor's transformed size.</para>
|
||
|
|
||
|
<para>The <varname>vertex</varname> contains the position
|
||
|
and color of a vertex, to be deformed by your effect.
|
||
|
Your <function>deform_vertex()</function>
|
||
|
function should modify the member variables of this
|
||
|
<type>CoglTextureVertex</type> in place. Usually, this will
|
||
|
mean modifying the <varname>x</varname>, <varname>y</varname>
|
||
|
and <varname>y</varname> member variables of the vertex,
|
||
|
which describe its position in 3D space.</para>
|
||
|
|
||
|
<para>The example function below, taken from
|
||
|
<link linkend="effects-custom-deform-example-2">the
|
||
|
full example</link>, applies a transformation to vertices falling
|
||
|
in the "right-hand" half of the actor (i.e. vertices with an
|
||
|
<varname>x</varname> value greater than or equal to half the
|
||
|
width of the actor).</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
static void
|
||
|
cb_page_fold_effect_deform_vertex (ClutterDeformEffect *effect,
|
||
|
gfloat width,
|
||
|
gfloat height,
|
||
|
CoglTextureVertex *vertex)
|
||
|
{
|
||
|
CbPageFoldEffectPrivate *priv = CB_PAGE_FOLD_EFFECT (effect)->priv;
|
||
|
|
||
|
/* the rotation angle is modified by the percentage progress of the fold,
|
||
|
* as represented by the period variable
|
||
|
*/
|
||
|
gfloat radians = (priv->angle * priv->period) / (180.0f / G_PI);
|
||
|
|
||
|
/* rotate from the center of the actor on the y axis */
|
||
|
gfloat adjusted_x = vertex->x - (width / 2);
|
||
|
|
||
|
/* only rotate vertices to the right of the middle of the actor */
|
||
|
if (adjusted_x >= 0.0)
|
||
|
{
|
||
|
vertex->x = (vertex->z * sin (radians))
|
||
|
+ (adjusted_x * cos (radians))
|
||
|
+ width / 2;
|
||
|
|
||
|
/* NB add 1 to z to prevent "z fighting"; otherwise, when fully-folded
|
||
|
* the image has "stripes" where vertices from the folded part
|
||
|
* of the actor interfere with vertices from the unfolded part
|
||
|
*/
|
||
|
vertex->z = (vertex->z * cos (radians))
|
||
|
+ (adjusted_x * sin (radians))
|
||
|
+ 1;
|
||
|
}
|
||
|
|
||
|
/* adjust depth of all vertices so they fit inside the actor while folding;
|
||
|
* this has the effect of making the image smaller within the texture,
|
||
|
* but does produce a cleaner fold animation
|
||
|
*/
|
||
|
vertex->z -= width / 2;
|
||
|
}
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>Note that this effect has two properties set in its
|
||
|
constructor or through setters:</para>
|
||
|
|
||
|
<orderedlist>
|
||
|
<listitem>
|
||
|
<para><varname>angle</varname>, representing the angle of
|
||
|
the full fold; for the actor to fully fold in half, this
|
||
|
would be set to 180.0</para>
|
||
|
</listitem>
|
||
|
|
||
|
<listitem>
|
||
|
<para><varname>period</varname>, representing the percentage
|
||
|
of the fold to apply</para>
|
||
|
</listitem>
|
||
|
</orderedlist>
|
||
|
|
||
|
<para>As well as rotating the vertex, the
|
||
|
<function>deform_vertex()</function> function also shifts
|
||
|
the <varname>z</varname> coordinate "up" by 1
|
||
|
(towards the viewpoint) for vertices on the right-hand side of the
|
||
|
actor. This is so that the "folded over" vertices
|
||
|
are above vertices on the left-hand side. Without this small
|
||
|
shift, the vertices interfere with each other, which can cause striping
|
||
|
artefacts.</para>
|
||
|
|
||
|
<para><emphasis>All</emphasis> vertices are also shifted "down",
|
||
|
so that the the folding part of the actor remains within the texture.
|
||
|
Otherwise the part which is folding may be clipped to the allocation of
|
||
|
the actor.</para>
|
||
|
|
||
|
<para>This effect can now be applied to an actor, using the
|
||
|
approach
|
||
|
<link linkend="effects-introduction-using-the-built-in-effects">outlined
|
||
|
in the introduction</link>. The result looks like this when
|
||
|
<varname>period</varname> is set to 0.25 and <varname>angle</varname>
|
||
|
to 180.0 (i.e. the page is folded by 45 degrees):</para>
|
||
|
|
||
|
<screenshot>
|
||
|
<mediaobject>
|
||
|
<imageobject>
|
||
|
<imagedata format="PNG"
|
||
|
fileref="images/effects-custom-deform.png" />
|
||
|
</imageobject>
|
||
|
<alt>
|
||
|
<para>Applying a custom <type>ClutterDeformEffect</type>
|
||
|
to a texture loaded with an image</para>
|
||
|
</alt>
|
||
|
</mediaobject>
|
||
|
</screenshot>
|
||
|
|
||
|
<para>Because the effect is a GObject which exposes its
|
||
|
properties, it can easily be animated, as described in
|
||
|
<link linkend="effects-custom-deform-discussion-animating">the
|
||
|
discussion section</link>.</para>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section id="effects-custom-deform-discussion">
|
||
|
<title>Discussion</title>
|
||
|
|
||
|
<para>A deform effect processes an actor as follows:</para>
|
||
|
|
||
|
<itemizedlist>
|
||
|
|
||
|
<listitem>
|
||
|
<para>The actor is divided into a series of
|
||
|
triangular tiles. The number of
|
||
|
horizontal and vertical tiles is configurable;
|
||
|
more tiles implies more vertices. See
|
||
|
<link linkend="effects-custom-deform-discussion-tiles">this
|
||
|
section</link> for more details about tiles.</para>
|
||
|
</listitem>
|
||
|
|
||
|
<listitem>
|
||
|
<para>The position of each vertex of each
|
||
|
tile is then modified (or not) by the
|
||
|
<function>deform_vertex()</function> function. In this
|
||
|
function, you can change the vertex's position
|
||
|
(<varname>x</varname>, <varname>y</varname>,
|
||
|
<varname>z</varname> coordinates). You can also
|
||
|
modify the color at the vertex if desired.</para>
|
||
|
|
||
|
<para>The resulting deformed vertices are stored
|
||
|
in an offscreen buffer.</para>
|
||
|
</listitem>
|
||
|
|
||
|
<listitem>
|
||
|
<para>Once the deformation has been applied to
|
||
|
all vertices, the content of the offscreen buffer
|
||
|
is painted at the onscreen position of the actor.</para>
|
||
|
</listitem>
|
||
|
|
||
|
</itemizedlist>
|
||
|
|
||
|
<para>You may find it useful to visualise this process by imagining
|
||
|
your actor's surface as a net, composed of triangles. (Something
|
||
|
like a fishing net, not a mathematical one.) At each corner of
|
||
|
each triangle is a marble; and between each pair of corners
|
||
|
is an infinitely flexible length of elastic. Moving a marble
|
||
|
doesn't change the position of its neighbours; it just stretches
|
||
|
or relaxes the elastic.</para>
|
||
|
|
||
|
<para>In this analogy, the marbles are the vertices; and the
|
||
|
surfaces between the marbles, bordered by triangles of
|
||
|
elastic, are the tiles. More triangles (tiles) means more
|
||
|
marbles (vertices).</para>
|
||
|
|
||
|
<para>When you create a <type>ClutterDeformEffect</type>,
|
||
|
think of it as specifying movements of marbles in the net.
|
||
|
Changing the position of a vertex corresponds to moving a marble
|
||
|
up/down (-/+ <varname>y</varname> position), left/right
|
||
|
(-/+ <varname>x</varname> position) or away/towards
|
||
|
you (-/+ <varname>z</varname> position) (ignoring color for the
|
||
|
moment).</para>
|
||
|
|
||
|
<para>Now imagine that you are asked to fold the whole net of
|
||
|
marbles; but you can't just grab the edge of the net and pull
|
||
|
it over: you can only move one marble at a time. However, once moved,
|
||
|
each marble magically stays where you put it in 3D space.</para>
|
||
|
|
||
|
<para>To do this, you could project where each marble would be if
|
||
|
you could fold the whole sheet in one go; then move the
|
||
|
marbles one by one to their projected positions. Even though
|
||
|
you'd be moving the marbles one at a time, it would eventually
|
||
|
look as though you'd folded the whole net with a single movement.</para>
|
||
|
|
||
|
<para>When you write a <type>ClutterDeformEffect</type>, you have
|
||
|
to accomplish a similar feat: change the shape of an actor
|
||
|
by individually modifying the positions of points on its surface. In
|
||
|
most cases, your <function>deform_vertex()</function> implementation
|
||
|
can take advantage of an existing geometric transformation
|
||
|
method to achieve this. (For example, the page fold in this recipe
|
||
|
is based on equations from p.412 of <citetitle pubwork="book">Computer
|
||
|
Graphics (C Version), 2nd Edition</citetitle> by Hearn and
|
||
|
Baker, 1996.)</para>
|
||
|
|
||
|
<section>
|
||
|
<title>Customising the back material</title>
|
||
|
|
||
|
<para>When you set up a deform effect, you
|
||
|
can optionally specify a material to use for the "back" of
|
||
|
any actor it is applied to.</para>
|
||
|
|
||
|
<para>If you think of an actor as a sheet of paper with a
|
||
|
picture on it, specifying a back is similar to turning the
|
||
|
sheet of paper over (rotating it around the
|
||
|
<varname>y</varname> axis) and drawing another picture on
|
||
|
the other side. If you then folded or twisted the paper,
|
||
|
you would be able to see parts of the pictures on both the
|
||
|
front and back of the paper.</para>
|
||
|
|
||
|
<para>Similarly, during deformation of an actor, if any
|
||
|
vertices of the actor are deformed such that the actor's surface
|
||
|
is folded or twisted over itself, parts of its back
|
||
|
become visible. If you set a back material, you will see parts
|
||
|
of that where the surface is folded over. If you don't set a back
|
||
|
material, you will instead see mirror images of parts of the actor's
|
||
|
front: as if the actor was flexible stained glass, rather than paper.
|
||
|
You can see this if you watch the animation in
|
||
|
<link linkend="effects-custom-deform-discussion-animating">this
|
||
|
section</link>.</para>
|
||
|
|
||
|
<para>The back material should be an instance of
|
||
|
<type>CoglMaterial</type>. You can either create this via
|
||
|
the Cogl API directly; or indirectly through the Clutter API
|
||
|
(for example, by getting the material from a
|
||
|
<type>ClutterTexture</type>). The code below gives an example
|
||
|
of how to do the latter:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
<![CDATA[
|
||
|
/* create a texture */
|
||
|
ClutterActor *back = clutter_texture_new ();
|
||
|
clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (back), TRUE);
|
||
|
clutter_actor_set_width (back, 400);
|
||
|
|
||
|
/* load image into texture (ignoring errors for brevity) */
|
||
|
clutter_texture_set_from_file (CLUTTER_TEXTURE (back),
|
||
|
back_image_file,
|
||
|
NULL);
|
||
|
|
||
|
/* get a handle to the texture's Cogl material */
|
||
|
CoglHandle material = clutter_texture_get_cogl_material (CLUTTER_TEXTURE (back));
|
||
|
|
||
|
/* cast the effect to ClutterDeformEffect and set its back material
|
||
|
* to the handle
|
||
|
*/
|
||
|
clutter_deform_effect_set_back_material (CLUTTER_DEFORM_EFFECT (effect),
|
||
|
material);
|
||
|
]]>
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>See the <type>ClutterDeformEffect</type> API reference
|
||
|
for more details about back materials.</para>
|
||
|
|
||
|
<para>Here's a screenshot of the
|
||
|
<link linkend="effects-custom-deform-example-3">example</link>
|
||
|
with the addition of a back material, folded at an angle
|
||
|
of 60 degrees:</para>
|
||
|
|
||
|
<screenshot>
|
||
|
<mediaobject>
|
||
|
<imageobject>
|
||
|
<imagedata format="PNG"
|
||
|
fileref="images/effects-custom-deform-back-material.png" />
|
||
|
</imageobject>
|
||
|
<alt>
|
||
|
<para>Applying a custom <type>ClutterDeformEffect</type>
|
||
|
to a texture loaded with an image</para>
|
||
|
</alt>
|
||
|
</mediaobject>
|
||
|
</screenshot>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section id="effects-custom-deform-discussion-animating">
|
||
|
<title>Animating a custom deform effect</title>
|
||
|
|
||
|
<para>Clutter's animation API can animate any GObject which
|
||
|
exposes its properties. In the case of the page fold effect,
|
||
|
we can expose the <varname>period</varname> property using
|
||
|
standard GObject property installation:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
/* GObject class init */
|
||
|
static void
|
||
|
cb_page_fold_effect_class_init (CbPageFoldEffectClass *klass)
|
||
|
{
|
||
|
GParamSpec *pspec;
|
||
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||
|
|
||
|
/* ...other class setup code... */
|
||
|
|
||
|
/* expose the period as a GObject property */
|
||
|
pspec = g_param_spec_double ("period",
|
||
|
"Period",
|
||
|
"The period of the page fold",
|
||
|
0.0, 1.0,
|
||
|
0.0,
|
||
|
G_PARAM_READWRITE);
|
||
|
obj_props[PROP_PERIOD] = pspec;
|
||
|
g_object_class_install_property (gobject_class, PROP_PERIOD, pspec);
|
||
|
|
||
|
/* ...install other properties... */
|
||
|
}
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>We also add a <function>get_property()</function>
|
||
|
implementation, as well as a setter (see
|
||
|
<link linkend="effects-custom-deform-example-2">the full
|
||
|
GObject implementation</link> for details).</para>
|
||
|
|
||
|
<para>Then set up an animation for the property; in this case,
|
||
|
using a <type>ClutterState</type>:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
ClutterEffect *effect = cb_page_fold_effect_new (180.0, 0.0);
|
||
|
|
||
|
ClutterState *transitions = clutter_state_new ();
|
||
|
clutter_state_set_duration (transitions, NULL, NULL, 500);
|
||
|
|
||
|
clutter_state_set (transitions, NULL, "unfolded",
|
||
|
effect, "period", CLUTTER_LINEAR, 0.0,
|
||
|
NULL);
|
||
|
|
||
|
clutter_state_set (transitions, NULL, "folded",
|
||
|
effect, "period", CLUTTER_LINEAR, 1.0,
|
||
|
NULL);
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>To start the animation, warp the <type>ClutterState</type>
|
||
|
into its <emphasis>"unfolded"</emphasis> state, then set it to
|
||
|
<emphasis>"folded"</emphasis>:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
/* this changes state instantaneously */
|
||
|
clutter_state_warp_to_state (transitions, "unfolded");
|
||
|
|
||
|
/* this starts an animation to the state */
|
||
|
clutter_state_set_state (transitions, "folded");
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>Note that the
|
||
|
<link linkend="effects-custom-deform-example-3">full code
|
||
|
sample</link> is slightly more complex, as it triggers state
|
||
|
changes when a mouse button is pressed on the texture. There is
|
||
|
also a third "partially folded" state (used to create
|
||
|
the screenshot for the
|
||
|
<link linkend="effects-custom-deform-solution">previous
|
||
|
section</link>).</para>
|
||
|
|
||
|
<para>Here's what the resulting animation looks like:</para>
|
||
|
|
||
|
<inlinemediaobject>
|
||
|
<videoobject>
|
||
|
<videodata fileref="videos/effects-custom-deform.ogv"/>
|
||
|
</videoobject>
|
||
|
<alt>
|
||
|
<para>Video showing animation of a custom deform effect
|
||
|
on a texture</para>
|
||
|
</alt>
|
||
|
</inlinemediaobject>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section id="effects-custom-deform-discussion-tiles">
|
||
|
<title>Tiles</title>
|
||
|
|
||
|
<para>A <type>ClutterDeformEffect</type> divides the actor
|
||
|
being deformed into a number of tiles: the larger the number
|
||
|
of tiles, the larger the number of vertices to be manipulated
|
||
|
by the effect. Increasing the number of tiles increases the number of
|
||
|
vertex computations required, which can slow down animations;
|
||
|
at the same time, finer-grained tiles can make an effect appear
|
||
|
smoother, particularly when animated.</para>
|
||
|
|
||
|
<para>Most of the time, the default number
|
||
|
of tiles in the <varname>x</varname> and <varname>y</varname>
|
||
|
axes should suffice. You can get the current number of
|
||
|
tiles associated with an effect with:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
<![CDATA[
|
||
|
guint x_tiles;
|
||
|
guint y_tiles;
|
||
|
|
||
|
/* effect must be a subclass of ClutterDeformEffect */
|
||
|
clutter_deform_effect_get_n_tiles (CLUTTER_DEFORM_EFFECT (effect),
|
||
|
&x_tiles,
|
||
|
&y_tiles);
|
||
|
]]>
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>However, if an effect produces jerky or fragmented output,
|
||
|
you want to tweak the number of tiles. Use the
|
||
|
<function>clutter_deform_effect_set_n_tiles()</function> function
|
||
|
to do this:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
/* 64 tiles in both axes */
|
||
|
guint x_tiles = 64;
|
||
|
guint y_tiles = 64;
|
||
|
|
||
|
clutter_deform_effect_set_n_tiles (CLUTTER_DEFORM_EFFECT (effect),
|
||
|
x_tiles,
|
||
|
y_tiles);
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<title>Full example</title>
|
||
|
|
||
|
<para>This example consists of three files:</para>
|
||
|
|
||
|
<itemizedlist>
|
||
|
<listitem>
|
||
|
<para><link linkend="effects-custom-deform-example-1">A header
|
||
|
file</link> for the <type>CbPageFoldEffect</type> GObject.</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para><link linkend="effects-custom-deform-example-2">The
|
||
|
code file</link> implementing <type>CbPageFoldEffect</type>.</para>
|
||
|
</listitem>
|
||
|
<listitem>
|
||
|
<para><link linkend="effects-custom-deform-example-3">A short
|
||
|
sample application</link> which applies a <type>CbPageFoldEffect</type>
|
||
|
instance to an actor and animates the fold when the actor is
|
||
|
clicked.</para>
|
||
|
</listitem>
|
||
|
</itemizedlist>
|
||
|
|
||
|
<para>As Clutter effect subclasses are written using GObject,
|
||
|
you might find <link linkend="actors-composite">this recipe</link>
|
||
|
(which goes into GObject in more detail) a useful introduction.</para>
|
||
|
|
||
|
<example id="effects-custom-deform-example-1">
|
||
|
<title><filename>cb-page-fold-effect.h</filename> (header file)</title>
|
||
|
<programlisting>
|
||
|
<xi:include href="examples/cb-page-fold-effect.h" parse="text">
|
||
|
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
||
|
</xi:include>
|
||
|
</programlisting>
|
||
|
</example>
|
||
|
|
||
|
<example id="effects-custom-deform-example-2">
|
||
|
<title><filename>cb-page-fold-effect.c</filename> (code file)</title>
|
||
|
<programlisting>
|
||
|
<xi:include href="examples/cb-page-fold-effect.c" parse="text">
|
||
|
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
||
|
</xi:include>
|
||
|
</programlisting>
|
||
|
</example>
|
||
|
|
||
|
<example id="effects-custom-deform-example-3">
|
||
|
<title>Application which uses <type>CbPageFoldEffect</type>
|
||
|
to do animated folding of a <type>ClutterTexture</type></title>
|
||
|
<programlisting>
|
||
|
<xi:include href="examples/effects-custom-deform.c" parse="text">
|
||
|
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
||
|
</xi:include>
|
||
|
</programlisting>
|
||
|
</example>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
</chapter>
|