mirror of
https://github.com/brl/mutter.git
synced 2024-12-12 14:20:17 +00:00
740 lines
22 KiB
C
740 lines
22 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>
|
||
|
*
|
||
|
* Based on the MxDeformTexture class, written by:
|
||
|
* Chris Lord <chris@linux.intel.com>
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* SECTION:clutter-deform-effect
|
||
|
* @Title: ClutterDeformEffect
|
||
|
* @Short_Description: A base class for effects deforming the geometry
|
||
|
* of an actor
|
||
|
*
|
||
|
* #ClutterDeformEffect is an abstract class providing all the plumbing
|
||
|
* for creating effects that result in the deformation of an actor's
|
||
|
* geometry.
|
||
|
*
|
||
|
* #ClutterDeformEffect uses offscreen buffers to render the contents of
|
||
|
* a #ClutterActor and then the Cogl vertex buffers API to submit the
|
||
|
* geomtry to the GPU.
|
||
|
*
|
||
|
* <refsect2>
|
||
|
* <title>Implementing ClutterDeformEffect</title>
|
||
|
* <para>Sub-classes of #ClutterDeformEffect should override the
|
||
|
* <function>deform_vertex()</function> virtual function; this function
|
||
|
* is called on every vertex that needs to be deformed by the effect.
|
||
|
* Each passed vertex is an in-out parameter that initially contains the
|
||
|
* position of the vertex and should be modified according to a specific
|
||
|
* deformation algorithm.</para>
|
||
|
* </refsect2>
|
||
|
*
|
||
|
* #ClutterDeformEffect is available since Clutter 1.4
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include "config.h"
|
||
|
#endif
|
||
|
|
||
|
#include "clutter-deform-effect.h"
|
||
|
|
||
|
#include <cogl/cogl.h>
|
||
|
|
||
|
#include "clutter-debug.h"
|
||
|
#include "clutter-enum-types.h"
|
||
|
#include "clutter-private.h"
|
||
|
|
||
|
#define DEFAULT_N_TILES 32
|
||
|
|
||
|
struct _ClutterDeformEffectPrivate
|
||
|
{
|
||
|
CoglHandle back_material;
|
||
|
|
||
|
gint x_tiles;
|
||
|
gint y_tiles;
|
||
|
|
||
|
CoglHandle vbo;
|
||
|
|
||
|
CoglHandle indices;
|
||
|
CoglHandle back_indices;
|
||
|
gint n_indices;
|
||
|
|
||
|
CoglTextureVertex *vertices;
|
||
|
|
||
|
gulong allocation_id;
|
||
|
|
||
|
guint is_dirty : 1;
|
||
|
};
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
PROP_0,
|
||
|
|
||
|
PROP_X_TILES,
|
||
|
PROP_Y_TILES,
|
||
|
|
||
|
PROP_BACK_MATERIAL
|
||
|
};
|
||
|
|
||
|
G_DEFINE_ABSTRACT_TYPE (ClutterDeformEffect,
|
||
|
clutter_deform_effect,
|
||
|
CLUTTER_TYPE_OFFSCREEN_EFFECT);
|
||
|
|
||
|
static void
|
||
|
clutter_deform_effect_real_deform_vertex (ClutterDeformEffect *effect,
|
||
|
gfloat width,
|
||
|
gfloat height,
|
||
|
CoglTextureVertex *vertex)
|
||
|
{
|
||
|
g_warning ("%s: Deformation effect of type '%s' does not implement "
|
||
|
"the required ClutterDeformEffect::deform_vertex virtual "
|
||
|
"function.",
|
||
|
G_STRLOC,
|
||
|
G_OBJECT_TYPE_NAME (effect));
|
||
|
}
|
||
|
|
||
|
void
|
||
|
_clutter_deform_effect_deform_vertex (ClutterDeformEffect *effect,
|
||
|
gfloat width,
|
||
|
gfloat height,
|
||
|
CoglTextureVertex *vertex)
|
||
|
{
|
||
|
CLUTTER_DEFORM_EFFECT_GET_CLASS (effect)->deform_vertex (effect,
|
||
|
width, height,
|
||
|
vertex);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
vbo_invalidate (ClutterActor *actor,
|
||
|
const ClutterActorBox *allocation,
|
||
|
ClutterAllocationFlags flags,
|
||
|
ClutterDeformEffect *effect)
|
||
|
{
|
||
|
effect->priv->is_dirty = TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
clutter_deform_effect_set_actor (ClutterActorMeta *meta,
|
||
|
ClutterActor *actor)
|
||
|
{
|
||
|
ClutterDeformEffectPrivate *priv = CLUTTER_DEFORM_EFFECT (meta)->priv;
|
||
|
|
||
|
if (priv->allocation_id != 0)
|
||
|
{
|
||
|
ClutterActor *old_actor = clutter_actor_meta_get_actor (meta);
|
||
|
|
||
|
g_signal_handler_disconnect (old_actor, priv->allocation_id);
|
||
|
priv->allocation_id = 0;
|
||
|
}
|
||
|
|
||
|
/* we need to invalidate the VBO whenever the allocation of the actor
|
||
|
* changes
|
||
|
*/
|
||
|
if (actor != NULL)
|
||
|
priv->allocation_id = g_signal_connect (actor, "allocation-changed",
|
||
|
G_CALLBACK (vbo_invalidate),
|
||
|
meta);
|
||
|
|
||
|
priv->is_dirty = TRUE;
|
||
|
|
||
|
CLUTTER_ACTOR_META_CLASS (clutter_deform_effect_parent_class)->set_actor (meta, actor);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect)
|
||
|
{
|
||
|
ClutterDeformEffect *self= CLUTTER_DEFORM_EFFECT (effect);
|
||
|
ClutterDeformEffectPrivate *priv = self->priv;
|
||
|
gboolean is_depth_enabled, is_cull_enabled;
|
||
|
CoglHandle material;
|
||
|
gint n_tiles;
|
||
|
|
||
|
if (priv->is_dirty)
|
||
|
{
|
||
|
ClutterActor *actor;
|
||
|
gfloat width, height;
|
||
|
guint opacity;
|
||
|
gint i, j;
|
||
|
|
||
|
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
|
||
|
opacity = clutter_actor_get_paint_opacity (actor);
|
||
|
clutter_actor_get_size (actor, &width, &height);
|
||
|
|
||
|
for (i = 0; i < priv->y_tiles + 1; i++)
|
||
|
{
|
||
|
for (j = 0; j < priv->x_tiles + 1; j++)
|
||
|
{
|
||
|
CoglTextureVertex *vertex;
|
||
|
|
||
|
vertex = &priv->vertices[(i * (priv->x_tiles + 1)) + j];
|
||
|
|
||
|
vertex->tx = (float) j / priv->x_tiles;
|
||
|
vertex->ty = (float) i / priv->y_tiles;
|
||
|
|
||
|
vertex->x = width * vertex->tx;
|
||
|
vertex->y = height * vertex->ty;
|
||
|
vertex->z = 0.0f;
|
||
|
|
||
|
cogl_color_set_from_4ub (&vertex->color, 255, 255, 255, opacity);
|
||
|
|
||
|
_clutter_deform_effect_deform_vertex (self, width, height, vertex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* XXX in theory, the sub-classes should tell us what they changed
|
||
|
* in the texture vertices; we then would be able to avoid resubmitting
|
||
|
* the same data, if it did not change. for the time being, we resubmit
|
||
|
* everything
|
||
|
*/
|
||
|
cogl_vertex_buffer_add (priv->vbo, "gl_Vertex",
|
||
|
3,
|
||
|
COGL_ATTRIBUTE_TYPE_FLOAT,
|
||
|
FALSE,
|
||
|
sizeof (CoglTextureVertex),
|
||
|
&priv->vertices->x);
|
||
|
cogl_vertex_buffer_add (priv->vbo, "gl_MultiTexCoord0",
|
||
|
2,
|
||
|
COGL_ATTRIBUTE_TYPE_FLOAT,
|
||
|
FALSE,
|
||
|
sizeof (CoglTextureVertex),
|
||
|
&priv->vertices->tx);
|
||
|
cogl_vertex_buffer_add (priv->vbo, "gl_Color",
|
||
|
4,
|
||
|
COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE,
|
||
|
FALSE,
|
||
|
sizeof (CoglTextureVertex),
|
||
|
&priv->vertices->color);
|
||
|
|
||
|
priv->is_dirty = FALSE;
|
||
|
}
|
||
|
|
||
|
/* enable depth test, if it's not already enabled */
|
||
|
is_depth_enabled = cogl_get_depth_test_enabled ();
|
||
|
if (!is_depth_enabled)
|
||
|
cogl_set_depth_test_enabled (TRUE);
|
||
|
|
||
|
/* enable backface culling if it's not already enabled and if
|
||
|
* we have a back material
|
||
|
*/
|
||
|
is_cull_enabled = cogl_get_backface_culling_enabled ();
|
||
|
if (priv->back_material != COGL_INVALID_HANDLE && !is_cull_enabled)
|
||
|
cogl_set_backface_culling_enabled (TRUE);
|
||
|
else if (priv->back_material == COGL_INVALID_HANDLE && is_cull_enabled)
|
||
|
cogl_set_backface_culling_enabled (FALSE);
|
||
|
|
||
|
n_tiles = (priv->x_tiles + 1) * (priv->y_tiles + 1);
|
||
|
|
||
|
/* draw the front */
|
||
|
material = clutter_offscreen_effect_get_target (effect);
|
||
|
if (material != COGL_INVALID_HANDLE)
|
||
|
{
|
||
|
cogl_set_source (material);
|
||
|
cogl_vertex_buffer_draw_elements (priv->vbo,
|
||
|
COGL_VERTICES_MODE_TRIANGLE_STRIP,
|
||
|
priv->indices,
|
||
|
0,
|
||
|
n_tiles,
|
||
|
0,
|
||
|
priv->n_indices);
|
||
|
}
|
||
|
|
||
|
/* draw the back */
|
||
|
material = priv->back_material;
|
||
|
if (material != COGL_INVALID_HANDLE)
|
||
|
{
|
||
|
cogl_set_source (priv->back_material);
|
||
|
cogl_vertex_buffer_draw_elements (priv->vbo,
|
||
|
COGL_VERTICES_MODE_TRIANGLE_STRIP,
|
||
|
priv->back_indices,
|
||
|
0,
|
||
|
n_tiles,
|
||
|
0,
|
||
|
priv->n_indices);
|
||
|
}
|
||
|
|
||
|
/* restore the previous state */
|
||
|
if (!is_depth_enabled)
|
||
|
cogl_set_depth_test_enabled (FALSE);
|
||
|
|
||
|
if (priv->back_material != COGL_INVALID_HANDLE && !is_cull_enabled)
|
||
|
cogl_set_backface_culling_enabled (FALSE);
|
||
|
else if (priv->back_material == COGL_INVALID_HANDLE && is_cull_enabled)
|
||
|
cogl_set_backface_culling_enabled (TRUE);
|
||
|
}
|
||
|
|
||
|
static inline void
|
||
|
clutter_deform_effect_free_arrays (ClutterDeformEffect *self)
|
||
|
{
|
||
|
ClutterDeformEffectPrivate *priv = self->priv;
|
||
|
|
||
|
if (priv->vbo != COGL_INVALID_HANDLE)
|
||
|
{
|
||
|
cogl_handle_unref (priv->vbo);
|
||
|
priv->vbo = COGL_INVALID_HANDLE;
|
||
|
}
|
||
|
|
||
|
if (priv->indices != COGL_INVALID_HANDLE)
|
||
|
{
|
||
|
cogl_handle_unref (priv->indices);
|
||
|
priv->indices = COGL_INVALID_HANDLE;
|
||
|
}
|
||
|
|
||
|
g_free (priv->vertices);
|
||
|
priv->vertices = NULL;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
clutter_deform_effect_init_arrays (ClutterDeformEffect *self)
|
||
|
{
|
||
|
ClutterDeformEffectPrivate *priv = self->priv;
|
||
|
GLushort *static_indices, *static_back_indices;
|
||
|
GLushort *idx, *back_idx;
|
||
|
gint x, y, direction;
|
||
|
gint n_tiles;
|
||
|
|
||
|
clutter_deform_effect_free_arrays (self);
|
||
|
|
||
|
priv->n_indices = (2 + 2 * priv->x_tiles)
|
||
|
* priv->y_tiles
|
||
|
+ (priv->y_tiles - 1);
|
||
|
|
||
|
static_indices = g_new (GLushort, priv->n_indices);
|
||
|
static_back_indices = g_new (GLushort, priv->n_indices);
|
||
|
|
||
|
#define MESH_INDEX(x,y) ((y) * (priv->x_tiles + 1) + (x))
|
||
|
|
||
|
/* compute all the triangles from the various tiles */
|
||
|
direction = 1;
|
||
|
|
||
|
idx = static_indices;
|
||
|
idx[0] = MESH_INDEX (0, 0);
|
||
|
idx[1] = MESH_INDEX (0, 1);
|
||
|
idx += 2;
|
||
|
|
||
|
back_idx = static_back_indices;
|
||
|
back_idx[0] = MESH_INDEX (priv->x_tiles, 0);
|
||
|
back_idx[1] = MESH_INDEX (priv->x_tiles, 1);
|
||
|
back_idx += 2;
|
||
|
|
||
|
for (y = 0; y < priv->y_tiles; y++)
|
||
|
{
|
||
|
for (x = 0; x < priv->x_tiles; x++)
|
||
|
{
|
||
|
if (direction)
|
||
|
{
|
||
|
idx[0] = MESH_INDEX (x + 1, y);
|
||
|
idx[1] = MESH_INDEX (x + 1, y + 1);
|
||
|
|
||
|
back_idx[0] = MESH_INDEX (priv->x_tiles - (x + 1), y);
|
||
|
back_idx[1] = MESH_INDEX (priv->x_tiles - (x + 1), y + 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
idx[0] = MESH_INDEX (priv->x_tiles - x - 1, y);
|
||
|
idx[1] = MESH_INDEX (priv->x_tiles - x - 1, y + 1);
|
||
|
|
||
|
back_idx[0] = MESH_INDEX (x + 1, y);
|
||
|
back_idx[1] = MESH_INDEX (x + 1, y + 1);
|
||
|
}
|
||
|
|
||
|
idx += 2;
|
||
|
back_idx += 2;
|
||
|
}
|
||
|
|
||
|
if (y == (priv->y_tiles - 1))
|
||
|
break;
|
||
|
|
||
|
if (direction)
|
||
|
{
|
||
|
idx[0] = MESH_INDEX (priv->x_tiles, y + 1);
|
||
|
idx[1] = MESH_INDEX (priv->x_tiles, y + 1);
|
||
|
idx[2] = MESH_INDEX (priv->x_tiles, y + 2);
|
||
|
|
||
|
back_idx[0] = MESH_INDEX (0, y + 1);
|
||
|
back_idx[1] = MESH_INDEX (0, y + 1);
|
||
|
back_idx[2] = MESH_INDEX (0, y + 2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
idx[0] = MESH_INDEX (0, y + 1);
|
||
|
idx[1] = MESH_INDEX (0, y + 1);
|
||
|
idx[2] = MESH_INDEX (0, y + 2);
|
||
|
|
||
|
back_idx[0] = MESH_INDEX (priv->x_tiles, y + 1);
|
||
|
back_idx[1] = MESH_INDEX (priv->x_tiles, y + 1);
|
||
|
back_idx[2] = MESH_INDEX (priv->x_tiles, y + 2);
|
||
|
}
|
||
|
|
||
|
idx += 3;
|
||
|
back_idx += 3;
|
||
|
|
||
|
direction = !direction;
|
||
|
}
|
||
|
|
||
|
#undef MESH_INDEX
|
||
|
|
||
|
priv->indices =
|
||
|
cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT,
|
||
|
static_indices,
|
||
|
priv->n_indices);
|
||
|
priv->back_indices =
|
||
|
cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT,
|
||
|
static_back_indices,
|
||
|
priv->n_indices);
|
||
|
|
||
|
g_free (static_indices);
|
||
|
g_free (static_back_indices);
|
||
|
|
||
|
n_tiles = (priv->x_tiles + 1) * (priv->y_tiles + 1);
|
||
|
priv->vertices = g_new (CoglTextureVertex, n_tiles);
|
||
|
priv->vbo = cogl_vertex_buffer_new (n_tiles);
|
||
|
|
||
|
priv->is_dirty = TRUE;
|
||
|
}
|
||
|
|
||
|
static inline void
|
||
|
clutter_deform_effect_free_back_material (ClutterDeformEffect *self)
|
||
|
{
|
||
|
ClutterDeformEffectPrivate *priv = self->priv;
|
||
|
|
||
|
if (priv->back_material != NULL)
|
||
|
{
|
||
|
cogl_handle_unref (priv->back_material);
|
||
|
priv->back_material = COGL_INVALID_HANDLE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
clutter_deform_effect_finalize (GObject *gobject)
|
||
|
{
|
||
|
ClutterDeformEffect *self = CLUTTER_DEFORM_EFFECT (gobject);
|
||
|
|
||
|
clutter_deform_effect_free_arrays (self);
|
||
|
clutter_deform_effect_free_back_material (self);
|
||
|
|
||
|
G_OBJECT_CLASS (clutter_deform_effect_parent_class)->finalize (gobject);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
clutter_deform_effect_set_property (GObject *gobject,
|
||
|
guint prop_id,
|
||
|
const GValue *value,
|
||
|
GParamSpec *pspec)
|
||
|
{
|
||
|
ClutterDeformEffect *self = CLUTTER_DEFORM_EFFECT (gobject);
|
||
|
|
||
|
switch (prop_id)
|
||
|
{
|
||
|
case PROP_X_TILES:
|
||
|
clutter_deform_effect_set_n_tiles (self, g_value_get_uint (value),
|
||
|
self->priv->y_tiles);
|
||
|
break;
|
||
|
|
||
|
case PROP_Y_TILES:
|
||
|
clutter_deform_effect_set_n_tiles (self, self->priv->x_tiles,
|
||
|
g_value_get_uint (value));
|
||
|
break;
|
||
|
|
||
|
case PROP_BACK_MATERIAL:
|
||
|
clutter_deform_effect_set_back_material (self, g_value_get_boxed (value));
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
clutter_deform_effect_get_property (GObject *gobject,
|
||
|
guint prop_id,
|
||
|
GValue *value,
|
||
|
GParamSpec *pspec)
|
||
|
{
|
||
|
ClutterDeformEffectPrivate *priv = CLUTTER_DEFORM_EFFECT (gobject)->priv;
|
||
|
|
||
|
switch (prop_id)
|
||
|
{
|
||
|
case PROP_X_TILES:
|
||
|
g_value_set_uint (value, priv->x_tiles);
|
||
|
break;
|
||
|
|
||
|
case PROP_Y_TILES:
|
||
|
g_value_set_uint (value, priv->y_tiles);
|
||
|
break;
|
||
|
|
||
|
case PROP_BACK_MATERIAL:
|
||
|
g_value_set_boxed (value, priv->back_material);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
clutter_deform_effect_class_init (ClutterDeformEffectClass *klass)
|
||
|
{
|
||
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||
|
ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
|
||
|
ClutterOffscreenEffectClass *offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
|
||
|
GParamSpec *pspec;
|
||
|
|
||
|
g_type_class_add_private (klass, sizeof (ClutterDeformEffectPrivate));
|
||
|
|
||
|
klass->deform_vertex = clutter_deform_effect_real_deform_vertex;
|
||
|
|
||
|
gobject_class->set_property = clutter_deform_effect_set_property;
|
||
|
gobject_class->get_property = clutter_deform_effect_get_property;
|
||
|
gobject_class->finalize = clutter_deform_effect_finalize;
|
||
|
|
||
|
/**
|
||
|
* ClutterDeformEffect:x-tiles:
|
||
|
*
|
||
|
* The number of horizontal tiles. The bigger the number, the
|
||
|
* smaller the tiles
|
||
|
*
|
||
|
* Since: 1.4
|
||
|
*/
|
||
|
pspec = g_param_spec_uint ("x-tiles",
|
||
|
"Horiontal Tiles",
|
||
|
"The number of horizontal tiles",
|
||
|
1, G_MAXUINT,
|
||
|
DEFAULT_N_TILES,
|
||
|
CLUTTER_PARAM_READWRITE);
|
||
|
g_object_class_install_property (gobject_class, PROP_X_TILES, pspec);
|
||
|
|
||
|
/**
|
||
|
* ClutterDeformEffect:y-tiles:
|
||
|
*
|
||
|
* The number of vertical tiles. The bigger the number, the
|
||
|
* smaller the tiles
|
||
|
*
|
||
|
* Since: 1.4
|
||
|
*/
|
||
|
pspec = g_param_spec_uint ("y-tiles",
|
||
|
"Vertical Tiles",
|
||
|
"The number of vertical tiles",
|
||
|
1, G_MAXUINT,
|
||
|
DEFAULT_N_TILES,
|
||
|
CLUTTER_PARAM_READWRITE);
|
||
|
g_object_class_install_property (gobject_class, PROP_Y_TILES, pspec);
|
||
|
|
||
|
/**
|
||
|
* ClutterDeformEffect:back-material:
|
||
|
*
|
||
|
* A material to be used when painting the back of the actor
|
||
|
* to which this effect has been applied
|
||
|
*
|
||
|
* By default, no material will be used
|
||
|
*
|
||
|
* Since: 1.4
|
||
|
*/
|
||
|
pspec = g_param_spec_boxed ("back-material",
|
||
|
"Back Material",
|
||
|
"The material to be used when painting the "
|
||
|
"back of the actor",
|
||
|
COGL_TYPE_HANDLE,
|
||
|
CLUTTER_PARAM_READWRITE);
|
||
|
g_object_class_install_property (gobject_class, PROP_BACK_MATERIAL, pspec);
|
||
|
|
||
|
meta_class->set_actor = clutter_deform_effect_set_actor;
|
||
|
|
||
|
offscreen_class->paint_target = clutter_deform_effect_paint_target;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
clutter_deform_effect_init (ClutterDeformEffect *self)
|
||
|
{
|
||
|
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_DEFORM_EFFECT,
|
||
|
ClutterDeformEffectPrivate);
|
||
|
|
||
|
self->priv->x_tiles = self->priv->y_tiles = DEFAULT_N_TILES;
|
||
|
self->priv->back_material = COGL_INVALID_HANDLE;
|
||
|
|
||
|
clutter_deform_effect_init_arrays (self);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* clutter_deform_effect_set_back_material:
|
||
|
* @effect: a #ClutterDeformEffect
|
||
|
* @material: (allow-none): a handle to a Cogl material
|
||
|
*
|
||
|
* Sets the material that should be used when drawing the back face
|
||
|
* of the actor during a deformation
|
||
|
*
|
||
|
* The #ClutterDeformEffect will take a reference on the material's
|
||
|
* handle
|
||
|
*
|
||
|
* Since: 1.4
|
||
|
*/
|
||
|
void
|
||
|
clutter_deform_effect_set_back_material (ClutterDeformEffect *effect,
|
||
|
CoglHandle material)
|
||
|
{
|
||
|
ClutterDeformEffectPrivate *priv;
|
||
|
|
||
|
g_return_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect));
|
||
|
g_return_if_fail (material == COGL_INVALID_HANDLE || cogl_is_material (material));
|
||
|
|
||
|
priv = effect->priv;
|
||
|
|
||
|
clutter_deform_effect_free_back_material (effect);
|
||
|
|
||
|
priv->back_material = material;
|
||
|
if (priv->back_material != COGL_INVALID_HANDLE)
|
||
|
cogl_handle_ref (priv->back_material);
|
||
|
|
||
|
clutter_deform_effect_invalidate (effect);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* clutter_deform_effect_get_back_material:
|
||
|
* @effect: a #ClutterDeformEffect
|
||
|
*
|
||
|
* Retrieves the handle to the back face material used by @effect
|
||
|
*
|
||
|
* Return value: (transfer none): a handle for the material, or %NULL.
|
||
|
* The returned material is owned by the #ClutterDeformEffect and it
|
||
|
* should not be freed directly
|
||
|
*
|
||
|
* Since: 1.4
|
||
|
*/
|
||
|
CoglHandle
|
||
|
clutter_deform_effect_get_back_material (ClutterDeformEffect *effect)
|
||
|
{
|
||
|
g_return_val_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect), NULL);
|
||
|
|
||
|
return effect->priv->back_material;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* clutter_deform_effect_set_n_tiles:
|
||
|
* @effect: a #ClutterDeformEffect
|
||
|
* @x_tiles: number of horizontal tiles
|
||
|
* @y_tiles: number of vertical tiles
|
||
|
*
|
||
|
* Sets the number of horizontal and vertical tiles to be used
|
||
|
* when applying the effect
|
||
|
*
|
||
|
* More tiles allow a finer grained deformation at the expenses
|
||
|
* of computation
|
||
|
*
|
||
|
* Since: 1.4
|
||
|
*/
|
||
|
void
|
||
|
clutter_deform_effect_set_n_tiles (ClutterDeformEffect *effect,
|
||
|
guint x_tiles,
|
||
|
guint y_tiles)
|
||
|
{
|
||
|
ClutterDeformEffectPrivate *priv;
|
||
|
gboolean tiles_changed = FALSE;
|
||
|
|
||
|
g_return_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect));
|
||
|
g_return_if_fail (x_tiles > 0 && y_tiles > 0);
|
||
|
|
||
|
priv = effect->priv;
|
||
|
|
||
|
g_object_freeze_notify (G_OBJECT (effect));
|
||
|
|
||
|
if (priv->x_tiles != x_tiles)
|
||
|
{
|
||
|
priv->x_tiles = x_tiles;
|
||
|
|
||
|
g_object_notify (G_OBJECT (effect), "x-tiles");
|
||
|
|
||
|
tiles_changed = TRUE;
|
||
|
}
|
||
|
|
||
|
if (priv->y_tiles != y_tiles)
|
||
|
{
|
||
|
priv->y_tiles = y_tiles;
|
||
|
|
||
|
g_object_notify (G_OBJECT (effect), "y-tiles");
|
||
|
|
||
|
tiles_changed = TRUE;
|
||
|
}
|
||
|
|
||
|
if (tiles_changed)
|
||
|
{
|
||
|
clutter_deform_effect_init_arrays (effect);
|
||
|
clutter_deform_effect_invalidate (effect);
|
||
|
}
|
||
|
|
||
|
g_object_thaw_notify (G_OBJECT (effect));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* clutter_deform_effect_get_n_tiles:
|
||
|
* @effect: a #ClutterDeformEffect
|
||
|
* @x_tiles: (out): return location for the number of horizontal tiles,
|
||
|
* or %NULL
|
||
|
* @y_tiles: (out): return location for the number of vertical tiles,
|
||
|
* or %NULL
|
||
|
*
|
||
|
* Retrieves the number of horizontal and vertical tiles used to sub-divide
|
||
|
* the actor's geometry during the effect
|
||
|
*
|
||
|
* Since: 1.4
|
||
|
*/
|
||
|
void
|
||
|
clutter_deform_effect_get_n_tiles (ClutterDeformEffect *effect,
|
||
|
guint *x_tiles,
|
||
|
guint *y_tiles)
|
||
|
{
|
||
|
g_return_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect));
|
||
|
|
||
|
if (x_tiles != NULL)
|
||
|
*x_tiles = effect->priv->x_tiles;
|
||
|
|
||
|
if (y_tiles != NULL)
|
||
|
*y_tiles = effect->priv->y_tiles;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* clutter_deform_effect_invalidate:
|
||
|
* @effect: a #ClutterDeformEffect
|
||
|
*
|
||
|
* Invalidates the @effect<!-- -->'s vertices and, if it is associated
|
||
|
* to an actor, it will queue a redraw
|
||
|
*
|
||
|
* Since: 1.4
|
||
|
*/
|
||
|
void
|
||
|
clutter_deform_effect_invalidate (ClutterDeformEffect *effect)
|
||
|
{
|
||
|
ClutterActor *actor;
|
||
|
|
||
|
g_return_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect));
|
||
|
|
||
|
if (effect->priv->is_dirty)
|
||
|
return;
|
||
|
|
||
|
effect->priv->is_dirty = TRUE;
|
||
|
|
||
|
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
|
||
|
if (actor != NULL)
|
||
|
clutter_actor_queue_redraw (actor);
|
||
|
}
|