74de3cfdf3
Add an effects chapter which gives a broad overview of the abstract classes in the effects API, plus a short example of how to apply one of the stock Clutter effects (ClutterColorizeEffect). The recipe explains how to create a custom ClutterDeformEffect to produce a page fold (code based on ClutterPageTurnEffect). The example code includes the effect class plus a small application to apply it to a texture.
251 lines
6.9 KiB
C
251 lines
6.9 KiB
C
#include <math.h>
|
|
#include "cb-page-fold-effect.h"
|
|
|
|
G_DEFINE_TYPE (CbPageFoldEffect, cb_page_fold_effect, CLUTTER_TYPE_DEFORM_EFFECT);
|
|
|
|
#define CB_PAGE_FOLD_EFFECT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
|
|
CB_TYPE_PAGE_FOLD_EFFECT, \
|
|
CbPageFoldEffectPrivate))
|
|
|
|
struct _CbPageFoldEffectPrivate
|
|
{
|
|
gdouble angle;
|
|
gdouble period;
|
|
};
|
|
|
|
enum {
|
|
PROP_0,
|
|
|
|
PROP_PERIOD,
|
|
PROP_ANGLE,
|
|
|
|
PROP_LAST
|
|
};
|
|
|
|
static GParamSpec *obj_props[PROP_LAST];
|
|
|
|
/* ClutterDeformEffect implementation */
|
|
static void
|
|
cb_page_fold_effect_deform_vertex (ClutterDeformEffect *effect,
|
|
gfloat width,
|
|
gfloat height,
|
|
CoglTextureVertex *vertex)
|
|
{
|
|
CbPageFoldEffectPrivate *priv = CB_PAGE_FOLD_EFFECT (effect)->priv;
|
|
|
|
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;
|
|
}
|
|
|
|
/* GObject implementation */
|
|
static void
|
|
cb_page_fold_effect_set_property (GObject *gobject,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
CbPageFoldEffect *effect = CB_PAGE_FOLD_EFFECT (gobject);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_PERIOD:
|
|
cb_page_fold_effect_set_period (effect, g_value_get_double (value));
|
|
break;
|
|
|
|
case PROP_ANGLE:
|
|
cb_page_fold_effect_set_angle (effect, g_value_get_double (value));
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
cb_page_fold_effect_get_property (GObject *gobject,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
CbPageFoldEffectPrivate *priv = CB_PAGE_FOLD_EFFECT (gobject)->priv;
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_PERIOD:
|
|
g_value_set_double (value, priv->period);
|
|
break;
|
|
|
|
case PROP_ANGLE:
|
|
g_value_set_double (value, priv->angle);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* GObject class and instance init */
|
|
static void
|
|
cb_page_fold_effect_class_init (CbPageFoldEffectClass *klass)
|
|
{
|
|
GParamSpec *pspec;
|
|
ClutterDeformEffectClass *effect_class = CLUTTER_DEFORM_EFFECT_CLASS (klass);
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
effect_class->deform_vertex = cb_page_fold_effect_deform_vertex;
|
|
|
|
gobject_class->set_property = cb_page_fold_effect_set_property;
|
|
gobject_class->get_property = cb_page_fold_effect_get_property;
|
|
|
|
g_type_class_add_private (klass, sizeof (CbPageFoldEffectPrivate));
|
|
|
|
/**
|
|
* CbPageFoldEffect:period:
|
|
*
|
|
* The period of the page fold, between 0.0 (no fold) and
|
|
* 1.0 (fully folded)
|
|
*/
|
|
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);
|
|
|
|
/**
|
|
* CbPageFoldEffect:angle:
|
|
*
|
|
* The angle of the page fold, in degrees, between 0.0 and 180.0
|
|
*/
|
|
pspec = g_param_spec_double ("angle",
|
|
"Angle",
|
|
"The angle of the page fold, in degrees",
|
|
0.0, 180.0,
|
|
0.0,
|
|
G_PARAM_READWRITE);
|
|
obj_props[PROP_ANGLE] = pspec;
|
|
g_object_class_install_property (gobject_class, PROP_ANGLE, pspec);
|
|
}
|
|
|
|
static void
|
|
cb_page_fold_effect_init (CbPageFoldEffect *self)
|
|
{
|
|
CbPageFoldEffectPrivate *priv;
|
|
|
|
priv = self->priv = CB_PAGE_FOLD_EFFECT_GET_PRIVATE (self);
|
|
|
|
priv->period = 0.0;
|
|
priv->angle = 0.0;
|
|
}
|
|
|
|
/* public API */
|
|
ClutterEffect *
|
|
cb_page_fold_effect_new (gdouble angle,
|
|
gdouble period)
|
|
{
|
|
return g_object_new (CB_TYPE_PAGE_FOLD_EFFECT,
|
|
"angle", angle,
|
|
"period", period,
|
|
NULL);
|
|
}
|
|
|
|
/**
|
|
* cb_page_fold_effect_set_period:
|
|
* @effect: a #CbPageFoldEffect
|
|
* @period: the period of the page fold, between 0.0 and 1.0
|
|
*
|
|
* Sets the period of the page fold, between 0.0 (no fold)
|
|
* and 1.0 (fully folded)
|
|
*/
|
|
void
|
|
cb_page_fold_effect_set_period (CbPageFoldEffect *effect,
|
|
gdouble period)
|
|
{
|
|
g_return_if_fail (CB_IS_PAGE_FOLD_EFFECT (effect));
|
|
g_return_if_fail (period >= 0.0 && period <= 1.0);
|
|
|
|
effect->priv->period = period;
|
|
|
|
clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect));
|
|
}
|
|
|
|
/**
|
|
* cb_page_fold_effect_get_period:
|
|
* @effect: a #CbPageFoldEffect
|
|
*
|
|
* Retrieves the value set using cb_page_fold_effect_get_period()
|
|
*
|
|
* Return value: the period of the page fold
|
|
*/
|
|
gdouble
|
|
cb_page_fold_effect_get_period (CbPageFoldEffect *effect)
|
|
{
|
|
g_return_val_if_fail (CB_IS_PAGE_FOLD_EFFECT (effect), 0.0);
|
|
|
|
return effect->priv->period;
|
|
}
|
|
|
|
/**
|
|
* cb_page_fold_effect_set_angle:
|
|
* @effect: #CbPageFoldEffect
|
|
* @angle: the angle of the page fold, in degrees
|
|
*
|
|
* Sets the angle of the page fold, in degrees; must be a value between
|
|
* 0.0 and 180.0
|
|
*/
|
|
void
|
|
cb_page_fold_effect_set_angle (CbPageFoldEffect *effect,
|
|
gdouble angle)
|
|
{
|
|
g_return_if_fail (CB_IS_PAGE_FOLD_EFFECT (effect));
|
|
g_return_if_fail (angle >= 0.0 && angle <= 180.0);
|
|
|
|
effect->priv->angle = angle;
|
|
|
|
clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect));
|
|
}
|
|
|
|
/**
|
|
* cb_page_fold_effect_get_angle:
|
|
* @effect: a #CbPageFoldEffect:
|
|
*
|
|
* Retrieves the angle of the page fold, in degrees
|
|
*
|
|
* Return value: the angle of the page fold
|
|
*/
|
|
gdouble
|
|
cb_page_fold_effect_get_angle (CbPageFoldEffect *effect)
|
|
{
|
|
g_return_val_if_fail (CB_IS_PAGE_FOLD_EFFECT (effect), 0.0);
|
|
|
|
return effect->priv->angle;
|
|
}
|