From 37bd35f592e13dfa8ded884fcf668409dec119f3 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 1 Jul 2009 13:59:13 +0100 Subject: [PATCH] [actor] Allow changing the transformations matrix Currently, the transformation matrix for an actor is constructed from scenegraph-related accessors. An actor, though, can call COGL API to add new transformations inside the paint() implementation, for instance: static void my_foo_paint (ClutterActor *a) { ... cogl_translate (-scroll_x, -scroll_y, 0); ... } Unfortunately these transformations will be completely ignored by the scenegraph machinery; for instance, getting the actor-relative coordinates from event coordinates is going to break badly because of this. In order to make the scenegraph aware of the potential of additional transformations, we need a ::apply_transform() virtual function. This vfunc will pass a CoglMatrix which can be used to apply additional operations: static void my_foo_apply_transform (ClutterActor *a, CoglMatrix *m) { CLUTTER_ACTOR_CLASS (my_foo_parent_class)->apply_transform (a, m); ... cogl_matrix_translate (m, -scroll_x, -scroll_y, 0); ... } The ::paint() implementation will be called with the actor already using the newly applied transformation matrix, as expected: static void my_foo_paint (ClutterActor *a) { ... } The ::apply_transform() implementations *must* chain up, so that the various transformations of each class are preserved. The default implementation inside ClutterActor applies all the transformations defined by the scenegraph-related accessors. Actors performing transformations inside the paint() function will continue to work as previously. --- clutter/clutter-actor.c | 104 +++++++++++++++++++++-------- clutter/clutter-actor.h | 15 ++++- doc/reference/clutter/clutter-sections.txt | 1 + 3 files changed, 89 insertions(+), 31 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 7f8b1e9..9b4d360 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -497,12 +497,12 @@ static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord); /* Helper macro which translates by the anchor coord, applies the given transformation and then translates back */ -#define TRANSFORM_ABOUT_ANCHOR_COORD(actor,coord,transform) G_STMT_START { \ - gfloat _tx, _ty, _tz; \ - clutter_anchor_coord_get_units ((actor), (coord), &_tx, &_ty, &_tz); \ - cogl_translate (_tx, _ty, _tz); \ - { transform; } \ - cogl_translate (-_tx, -_ty, -_tz); } G_STMT_END +#define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \ + gfloat _tx, _ty, _tz; \ + clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \ + cogl_matrix_translate ((m), _tx, _ty, _tz); \ + { _transform; } \ + cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterActor, clutter_actor, @@ -2119,25 +2119,23 @@ clutter_actor_get_abs_allocation_vertices (ClutterActor *self, verts); } -/* Applies the transforms associated with this actor to the - * OpenGL modelview matrix. - * - * This function does not push/pop matrix; it is the responsibility - * of the caller to do so as appropriate - */ static void -_clutter_actor_apply_modelview_transform (ClutterActor *self) +clutter_actor_real_apply_transform (ClutterActor *self, + CoglMatrix *matrix) { ClutterActorPrivate *priv = self->priv; - gboolean is_stage = CLUTTER_IS_STAGE (self); + gboolean is_stage = CLUTTER_IS_STAGE (self); if (!is_stage) - cogl_translate (priv->allocation.x1, - priv->allocation.y1, - 0); + { + cogl_matrix_translate (matrix, + priv->allocation.x1, + priv->allocation.y1, + 0.0); + } if (priv->z) - cogl_translate (0, 0, priv->z); + cogl_matrix_translate (matrix, 0, 0, priv->z); /* * because the rotation involves translations, we must scale before @@ -2147,37 +2145,66 @@ _clutter_actor_apply_modelview_transform (ClutterActor *self) */ if (priv->scale_x != 1.0 || priv->scale_y != 1.0) { - TRANSFORM_ABOUT_ANCHOR_COORD (self, + TRANSFORM_ABOUT_ANCHOR_COORD (self, matrix, &priv->scale_center, - cogl_scale (priv->scale_x, - priv->scale_y, - 1.0)); + cogl_matrix_scale (matrix, + priv->scale_x, + priv->scale_y, + 1.0)); } if (priv->rzang) - TRANSFORM_ABOUT_ANCHOR_COORD (self, + TRANSFORM_ABOUT_ANCHOR_COORD (self, matrix, &priv->rz_center, - cogl_rotate (priv->rzang, 0, 0, 1.0)); + cogl_matrix_rotate (matrix, + priv->rzang, + 0, 0, 1.0)); if (priv->ryang) - TRANSFORM_ABOUT_ANCHOR_COORD (self, + TRANSFORM_ABOUT_ANCHOR_COORD (self, matrix, &priv->ry_center, - cogl_rotate (priv->ryang, 0, 1.0, 0)); + cogl_matrix_rotate (matrix, + priv->ryang, + 0, 1.0, 0)); if (priv->rxang) - TRANSFORM_ABOUT_ANCHOR_COORD (self, + TRANSFORM_ABOUT_ANCHOR_COORD (self, matrix, &priv->rx_center, - cogl_rotate (priv->rxang, 1.0, 0, 0)); + cogl_matrix_rotate (matrix, + priv->rxang, + 1.0, 0, 0)); if (!is_stage && !clutter_anchor_coord_is_zero (&priv->anchor)) { gfloat x, y, z; clutter_anchor_coord_get_units (self, &priv->anchor, &x, &y, &z); - cogl_translate (-x, -y, -z); + cogl_matrix_translate (matrix, -x, -y, -z); } } +/* Applies the transforms associated with this actor to the + * OpenGL modelview matrix. + * + * This function does not push/pop matrix; it is the responsibility + * of the caller to do so as appropriate + */ +static void +_clutter_actor_apply_modelview_transform (ClutterActor *self) +{ + CoglMatrix matrix, cur, new; + + cogl_matrix_init_identity (&matrix); + + clutter_actor_get_transformation_matrix (self, &matrix); + + cogl_get_modelview_matrix (&cur); + + cogl_matrix_multiply (&new, &cur, &matrix); + + cogl_set_modelview_matrix (&new); +} + /* Recursively applies the transforms associated with this actor and * its ancestors to the OpenGL modelview matrix. Use NULL if you want this * to go all the way down to the stage. @@ -4229,6 +4256,7 @@ clutter_actor_class_init (ClutterActorClass *klass) klass->get_preferred_height = clutter_actor_real_get_preferred_height; klass->allocate = clutter_actor_real_allocate; klass->queue_redraw = clutter_actor_real_queue_redraw; + klass->apply_transform = clutter_actor_real_apply_transform; } static void @@ -9163,3 +9191,21 @@ clutter_actor_unset_flags (ClutterActor *self, g_object_thaw_notify (obj); } + +/** + * clutter_actor_get_transformation_matrix: + * @self: a #ClutterActor + * @matrix: (out): the return location for a #CoglMatrix + * + * Retrieves the transformations applied to @self + * + * Since: 1.0 + */ +void +clutter_actor_get_transformation_matrix (ClutterActor *self, + CoglMatrix *matrix) +{ + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix); +} diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index 365006b..080d257 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -178,7 +178,11 @@ struct _ClutterActor * and natural heights of an actor for a given width; it is used by * clutter_actor_get_preferred_height() * @allocate: virtual function, used when settings the coordinates of an - * actor; it is used by clutter_actor_allocate() + * actor; it is used by clutter_actor_allocate(); it must chain up to + * the parent's implementation + * @apply_transform: virtual function, used when applying the transformations + * to an actor before painting it or when transforming coordinates or + * the allocation; it must chain up to the parent's implementation * @parent_set: signal class handler for the #ClutterActor::parent-set * @destroy: signal class handler for #ClutterActor::destroy * @pick: virtual function, used to draw an outline of the actor with @@ -238,6 +242,11 @@ struct _ClutterActorClass void (* allocate) (ClutterActor *actor, const ClutterActorBox *box, ClutterAllocationFlags flags); + + /* transformations */ + void (* apply_transform) (ClutterActor *actor, + CoglMatrix *matrix); + /* event signals */ gboolean (* event) (ClutterActor *actor, ClutterEvent *event); @@ -325,7 +334,6 @@ void clutter_actor_get_allocation_geometry (ClutterActor void clutter_actor_get_allocation_vertices (ClutterActor *self, ClutterActor *ancestor, ClutterVertex verts[4]); - void clutter_actor_set_geometry (ClutterActor *self, const ClutterGeometry *geometry); void clutter_actor_get_geometry (ClutterActor *self, @@ -514,6 +522,9 @@ PangoContext *clutter_actor_create_pango_context (ClutterActor *self PangoLayout * clutter_actor_create_pango_layout (ClutterActor *self, const gchar *text); +void clutter_actor_get_transformation_matrix (ClutterActor *self, + CoglMatrix *matrix); + G_END_DECLS #endif /* __CLUTTER_ACTOR_H__ */ diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index cdc3f84..109a662 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -363,6 +363,7 @@ clutter_actor_get_transformed_size clutter_actor_get_paint_opacity clutter_actor_get_paint_visibility clutter_actor_get_abs_allocation_vertices +clutter_actor_get_transformation_matrix clutter_actor_set_anchor_point -- 2.7.4