From 94ce747f83b09c93351a06db233742f3b9255380 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 16 Aug 2010 15:53:28 +0100 Subject: [PATCH] actor: Allow querying the paint volume An actor has an implicit "paint volume", that is the volume in 3D space occupied when painting itself. The paint volume is defined as a cuboid with the origin placed at the top-left corner of the actor; the size of the cuboid is given by three vectors: width, height and depth. ClutterActor provides API to convert the paint volume into a 2D box in screen coordinates, to compute the on-screen area that an actor will occupy when painted. Actors can override the default implementation of the get_paint_volume() virtual function to provide a different volume. --- clutter/clutter-actor.c | 269 ++++++++++++++++++++++++++++++++++++++ clutter/clutter-actor.h | 8 +- clutter/clutter-private.h | 4 + clutter/clutter-types.h | 29 +++- 4 files changed, 305 insertions(+), 5 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index a0a3fa7fe..e811d4f7b 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -312,6 +312,37 @@ typedef struct _AnchorCoord AnchorCoord; #define CLUTTER_ACTOR_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate)) +/** + * ClutterPaintVolume: + * + * ClutterPaintVolume is an opaque structure whose + * members cannot be directly accessed + * + * Since: 1.4 + */ +struct _ClutterPaintVolume +{ + ClutterActor *actor; + + /* cuboid for the volume: + * + * 0: origin ┐ + * 1: width │→ plane[0], Z value = 0 + * 2: height ┘ + * + * 3. depth → X = 0, Y = 0, Z = @actor:depth + * + * 4: anti-origin ┐ + * 5: width │→ plane[1], Z value = @actor:depth + * 6: height ┘ + * + * 7: depth → X = anti-origin.x, Y = anti-origin.y, Z = @actor:depth + * + * the first four elements are filled in by the PaintVolume setters + */ + ClutterVertex vertices[8]; +}; + /* Internal helper struct to represent a point that can be stored in either direct pixel coordinates or as a fraction of the actor's size. It is used for the anchor point, scale center and rotation @@ -3223,6 +3254,19 @@ atk_implementor_iface_init (AtkImplementorIface *iface) iface->ref_accessible = _clutter_actor_ref_accessible; } +static void +clutter_actor_real_get_paint_volume (ClutterActor *self, + ClutterPaintVolume *volume) +{ + ClutterActorPrivate *priv = self->priv; + + /* the default origin is set to { 0, 0, 0 } */ + + clutter_paint_volume_set_width (volume, priv->allocation.x2 - priv->allocation.x1); + clutter_paint_volume_set_height (volume, priv->allocation.y2 - priv->allocation.y1); + clutter_paint_volume_set_depth (volume, priv->z); +} + static void clutter_actor_class_init (ClutterActorClass *klass) { @@ -4633,6 +4677,7 @@ clutter_actor_class_init (ClutterActorClass *klass) klass->queue_relayout = clutter_actor_real_queue_relayout; klass->apply_transform = clutter_actor_real_apply_transform; klass->get_accessible = clutter_actor_real_get_accessible; + klass->get_paint_volume = clutter_actor_real_get_paint_volume; } static void @@ -11438,3 +11483,227 @@ clutter_actor_has_key_focus (ClutterActor *self) return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self; } + +GType +clutter_paint_volume_get_type (void) +{ + static GType our_type = 0; + + if (G_UNLIKELY (our_type == 0)) + our_type = + g_boxed_type_register_static (I_("ClutterPaintVolume"), + (GBoxedCopyFunc) clutter_paint_volume_copy, + (GBoxedFreeFunc) clutter_paint_volume_free); + + return our_type; +} + +ClutterPaintVolume * +_clutter_paint_volume_new (ClutterActor *actor) +{ + ClutterPaintVolume *pv; + + pv = g_slice_new (ClutterPaintVolume); + pv->actor = (actor != NULL) ? g_object_ref (actor) : NULL; + + memset (pv->vertices, 0, 8 * sizeof (ClutterVertex)); + + return pv; +} + +ClutterPaintVolume * +clutter_paint_volume_copy (const ClutterPaintVolume *pv) +{ + ClutterPaintVolume *copy; + + if (G_UNLIKELY (pv == NULL)) + return NULL; + + copy = g_slice_dup (ClutterPaintVolume, pv); + copy->actor = g_object_ref (pv->actor); + + return copy; +} + +void +clutter_paint_volume_free (ClutterPaintVolume *pv) +{ + if (G_UNLIKELY (pv == NULL)) + { + if (pv->actor != NULL) + g_object_unref (pv->actor); + + g_slice_free (ClutterPaintVolume, pv); + } +} + +void +clutter_paint_volume_set_origin (ClutterPaintVolume *pv, + const ClutterVertex *origin) +{ + g_return_if_fail (pv != NULL); + + pv->vertices[0] = *origin; +} + +void +clutter_paint_volume_get_origin (const ClutterPaintVolume *pv, + ClutterVertex *vertex) +{ + g_return_if_fail (pv != NULL); + g_return_if_fail (vertex != NULL); + + *vertex = pv->vertices[0]; +} + +void +clutter_paint_volume_set_width (ClutterPaintVolume *pv, + gfloat width) +{ + g_return_if_fail (pv != NULL); + g_return_if_fail (width >= 0.0f); + + pv->vertices[1].x = width; +} + +gfloat +clutter_paint_volume_get_width (const ClutterPaintVolume *pv) +{ + g_return_val_if_fail (pv != NULL, 0.0); + + return pv->vertices[1].x; +} + +void +clutter_paint_volume_set_height (ClutterPaintVolume *pv, + gfloat height) +{ + g_return_if_fail (pv != NULL); + g_return_if_fail (height >= 0.0f); + + pv->vertices[2].y = height; +} + +gfloat +clutter_paint_volume_get_height (const ClutterPaintVolume *pv) +{ + g_return_val_if_fail (pv != NULL, 0.0); + + return pv->vertices[2].y; +} + +void +clutter_paint_volume_set_depth (ClutterPaintVolume *pv, + gfloat depth) +{ + g_return_if_fail (pv != NULL); + + pv->vertices[3].z = depth; +} + +gfloat +clutter_paint_volume_get_depth (const ClutterPaintVolume *pv) +{ + g_return_val_if_fail (pv != NULL, 0.0); + + return pv->vertices[3].z; +} + +void +_clutter_paint_volume_get_box (ClutterPaintVolume *pv, + ClutterActorBox *box) +{ + ClutterVertex screen_v[8]; + gfloat x_min, y_min, x_max, y_max; + gint i; + + g_return_if_fail (pv != NULL); + g_return_if_fail (box != NULL); + + if (pv->actor == NULL) + { + g_warning ("Paint volume created without a reference actor"); + return; + } + + /* anti-origin */ + pv->vertices[4].x = pv->vertices[1].x; + pv->vertices[4].y = pv->vertices[2].y; + pv->vertices[4].z = 0.0f; + + if (pv->vertices[3].z < 0.00001 || pv->vertices[3].z > 0.00001) + { + pv->vertices[5].x = pv->vertices[1].x; + pv->vertices[5].y = pv->vertices[0].y; + pv->vertices[5].z = pv->vertices[3].z; + + pv->vertices[6].x = pv->vertices[0].x; + pv->vertices[6].y = pv->vertices[2].y; + pv->vertices[6].z = pv->vertices[3].z; + + pv->vertices[7].x = pv->vertices[1].x; + pv->vertices[7].y = pv->vertices[2].y; + pv->vertices[7].z = pv->vertices[3].z; + } + + if (!_clutter_actor_fully_transform_vertices (pv->actor, + pv->vertices, + screen_v, + G_N_ELEMENTS (screen_v))) + return; + + box->x1 = box->y1 = box->x2 = box->y2 = 0.0f; + + x_min = y_min = G_MAXFLOAT; + x_max = y_max = -G_MAXFLOAT; + + for (i = 0; i < G_N_ELEMENTS (screen_v); i++) + { + if (screen_v[i].x < x_min) + x_min = screen_v[i].x; + + if (screen_v[i].x > x_max) + x_max = screen_v[i].x; + + if (screen_v[i].y < y_min) + y_min = screen_v[i].y; + + if (screen_v[i].y > y_max) + y_max = screen_v[i].y; + } + + box->x1 = x_min; + box->y1 = y_min; + box->x2 = x_max; + box->y2 = y_max; + clutter_actor_box_clamp_to_pixel (box); +} + +ClutterPaintVolume * +clutter_actor_get_paint_volume (ClutterActor *self) +{ + ClutterPaintVolume *pv; + + g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); + + pv = _clutter_paint_volume_new (self); + CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv); + + return pv; +} + +void +clutter_actor_get_paint_box (ClutterActor *self, + ClutterActorBox *box) +{ + ClutterPaintVolume *pv; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + g_return_if_fail (box != NULL); + + pv = clutter_actor_get_paint_volume (self); + + _clutter_paint_volume_get_box (pv, box); + + clutter_paint_volume_free (pv); +} diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index 0aac1011c..ab9306159 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -306,9 +306,12 @@ struct _ClutterActorClass /* accessibility support */ AtkObject * (* get_accessible) (ClutterActor *actor); + void (* get_paint_volume) (ClutterActor *actor, + ClutterPaintVolume *volume); + /*< private >*/ /* padding for future expansion */ - gpointer _padding_dummy[30]; + gpointer _padding_dummy[29]; }; GType clutter_actor_get_type (void) G_GNUC_CONST; @@ -586,6 +589,9 @@ gboolean clutter_actor_has_allocation (ClutterActor *sel AtkObject * clutter_actor_get_accessible (ClutterActor *self); gboolean clutter_actor_has_key_focus (ClutterActor *self); +ClutterPaintVolume *clutter_actor_get_paint_volume (ClutterActor *self); +void clutter_actor_get_paint_box (ClutterActor *self, + ClutterActorBox *box); G_END_DECLS diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index 9bc987e19..3e8c9bef7 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -409,6 +409,10 @@ gpointer _clutter_event_get_platform_data (const ClutterEvent *event); #endif +ClutterPaintVolume *_clutter_paint_volume_new (ClutterActor *actor); +void _clutter_paint_volume_get_box (ClutterPaintVolume *pv, + ClutterActorBox *box); + G_END_DECLS #endif /* _HAVE_CLUTTER_PRIVATE_H */ diff --git a/clutter/clutter-types.h b/clutter/clutter-types.h index b528f9ffc..cbe13d650 100644 --- a/clutter/clutter-types.h +++ b/clutter/clutter-types.h @@ -33,10 +33,11 @@ G_BEGIN_DECLS -#define CLUTTER_TYPE_ACTOR_BOX (clutter_actor_box_get_type ()) -#define CLUTTER_TYPE_GEOMETRY (clutter_geometry_get_type ()) -#define CLUTTER_TYPE_KNOT (clutter_knot_get_type ()) -#define CLUTTER_TYPE_VERTEX (clutter_vertex_get_type ()) +#define CLUTTER_TYPE_ACTOR_BOX (clutter_actor_box_get_type ()) +#define CLUTTER_TYPE_GEOMETRY (clutter_geometry_get_type ()) +#define CLUTTER_TYPE_KNOT (clutter_knot_get_type ()) +#define CLUTTER_TYPE_PAINT_VOLUME (clutter_paint_volume_get_type ()) +#define CLUTTER_TYPE_VERTEX (clutter_vertex_get_type ()) /* Forward delarations to avoid header catch 22's */ typedef struct _ClutterActor ClutterActor; @@ -90,6 +91,7 @@ typedef struct _ClutterActorBox ClutterActorBox; typedef struct _ClutterGeometry ClutterGeometry; typedef struct _ClutterKnot ClutterKnot; typedef struct _ClutterVertex ClutterVertex; +typedef struct _ClutterPaintVolume ClutterPaintVolume; /** * ClutterVertex: @@ -433,6 +435,25 @@ typedef enum { CLUTTER_FRAGMENT_SHADER } ClutterShaderType; +GType clutter_paint_volume_get_type (void) G_GNUC_CONST; + +ClutterPaintVolume *clutter_paint_volume_copy (const ClutterPaintVolume *pv); +void clutter_paint_volume_free (ClutterPaintVolume *pv); + +void clutter_paint_volume_set_origin (ClutterPaintVolume *pv, + const ClutterVertex *origin); +void clutter_paint_volume_get_origin (const ClutterPaintVolume *pv, + ClutterVertex *vertex); +void clutter_paint_volume_set_width (ClutterPaintVolume *pv, + gfloat width); +gfloat clutter_paint_volume_get_width (const ClutterPaintVolume *pv); +void clutter_paint_volume_set_height (ClutterPaintVolume *pv, + gfloat height); +gfloat clutter_paint_volume_get_height (const ClutterPaintVolume *pv); +void clutter_paint_volume_set_depth (ClutterPaintVolume *pv, + gfloat depth); +gfloat clutter_paint_volume_get_depth (const ClutterPaintVolume *pv); + G_END_DECLS #endif /* __CLUTTER_TYPES_H__ */