From a1b240d31b34ecb39f94b11c5a8d2a782965263f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Kol=C3=A5s?= Date: Tue, 13 May 2008 18:40:14 +0000 Subject: [PATCH] Made it possible to do picking when the colors stored in the framebuffer are only approximately the correct value. * clutter/clutter-actor.c: (init_bits): initialize constants about how many bits are available/will be used for r,g,b components. (_clutter_pix_to_id): now own function, compute an id from a pixel into its own function (used from _clutter_do_pick). (_clutter_id_to_col): now own function, computes the color to use for a given id. (clutter_actor_paint): use clutter_id_to_col. * clutter/clutter-main.c: (_clutter_do_pick): use _clutter_pix_to_id (clutter_main): re-enable invocation of fruity app shell. --- ChangeLog | 17 ++++++++ clutter/clutter-actor.c | 97 ++++++++++++++++++++++++++++++++++++----- clutter/clutter-main.c | 15 ++++--- 3 files changed, 111 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index a24b4a7b6..2a1ab47cf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2008-05-13 Øyvind Kolås + + Made it possible to do picking when the colors stored in the + framebuffer are only approximately the correct value. + + * clutter/clutter-actor.c: + (init_bits): initialize constants about how many bits are + available/will be used for r,g,b components. + (_clutter_pix_to_id): now own function, compute an id from a + pixel into its own function (used from _clutter_do_pick). + (_clutter_id_to_col): now own function, computes the color to use for + a given id. + (clutter_actor_paint): use clutter_id_to_col. + * clutter/clutter-main.c: + (_clutter_do_pick): use _clutter_pix_to_id + (clutter_main): re-enable invocation of fruity app shell. + 2008-05-13 Emmanuele Bassi * clutter/fruity/clutter-stage-fruity.c: diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 27dd805d1..d16daecdf 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -1211,6 +1211,91 @@ _clutter_actor_apply_modelview_transform_recursive (ClutterActor *self, _clutter_actor_apply_modelview_transform (self); } +static gint r_available, g_available, b_available; +static gint r_used, g_used, b_used; + +static inline void init_bits (void) +{ + static gboolean done = FALSE; + if (G_LIKELY (done)) + return; + done = TRUE; + cogl_get_bitmasks (&r_available, &g_available, &b_available, NULL); + + r_used = r_available; + g_used = g_available; + b_used = b_available; + +#ifndef HAVE_CLUTTER_FRUITY + /* We always do fuzzy picking for the fruity backend */ + if (g_getenv ("CLUTTER_FUZZY_PICK")!=NULL) +#endif + { + r_used--; + g_used--; + b_used--; + } +} + + +static inline void +_clutter_id_to_col (guint id, + ClutterColor *col) +{ + gint red, green, blue; + + init_bits (); + + /* compute the numbers we'll store in the components */ + red = (id >> (g_used+b_used)) & (0xff >> (8-r_used)); + green = (id >> b_used) & (0xff >> (8-g_used)); + blue = (id) & (0xff >> (8-b_used)); + + /* shift left bits a bit and add one, this circumvents + * at least some potential rounding errors in GL/GLES + * driver / hw implementation. + */ + if (r_used != r_available) + red = red * 2 + 1; + if (g_used != g_available) + green = green * 2 + 1; + if (b_used != b_available) + blue = blue * 2 + 1; + + /* shift up to be full 8bit values */ + red = red << (8-r_available); + green = green << (8-g_available); + blue = blue << (8-b_available); + + col->red = red; + col->green = green; + col->blue = blue; + col->alpha = 0xff; +} + +guint _clutter_pix_to_id (guchar pixel[4]) +{ + gint red, green, blue; + guint id; + + /* reduce the pixel components to the number of bits actually used of the + * 8bits. + */ + red = pixel[0] >> (8 - r_available); + green = pixel[1] >> (8 - g_available); + blue = pixel[2] >> (8 - b_available); + + /* divide by two */ + red = red >> (r_available-r_used); + green = green >> (g_available-g_used); + blue = blue >> (b_available-b_used); + + /* combine the correct per component values into the final id */ + id = blue + (green << b_used) + (red << (b_used + g_used)); + + return id; +} + /** * clutter_actor_paint: * @self: A #ClutterActor @@ -1256,19 +1341,9 @@ clutter_actor_paint (ClutterActor *self) if (G_UNLIKELY(context->pick_mode != CLUTTER_PICK_NONE)) { - gint r, g, b; ClutterColor col; - guint32 id; - id = clutter_actor_get_gid (self); - - cogl_get_bitmasks (&r, &g, &b, NULL); - - /* Encode the actor id into a color, taking into account bpp */ - col.red = ((id >> (g+b)) & (0xff>>(8-r)))<<(8-r); - col.green = ((id >> b) & (0xff>>(8-g))) << (8-g); - col.blue = (id & (0xff>>(8-b)))<<(8-b); - col.alpha = 0xff; + _clutter_id_to_col (clutter_actor_get_gid (self), &col); /* Actor will then paint silhouette of itself in supplied * color. See clutter_stage_get_actor_at_pos() for where diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index dc12a426e..a134518ea 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -226,6 +226,8 @@ clutter_get_motion_events_enabled (void) return context->motion_events_per_actor; } +guint _clutter_pix_to_id (guchar pixel[4]); + ClutterActor * _clutter_do_pick (ClutterStage *stage, gint x, @@ -237,8 +239,7 @@ _clutter_do_pick (ClutterStage *stage, GLint viewport[4]; ClutterColor white = { 0xff, 0xff, 0xff, 0xff }; guint32 id; - gint r,g,b; - + context = clutter_context_get_default (); _clutter_backend_ensure_context (context->backend, stage); @@ -273,10 +274,7 @@ _clutter_do_pick (ClutterStage *stage, if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff) return CLUTTER_ACTOR (stage); - cogl_get_bitmasks (&r, &g, &b, NULL); - - /* Decode color back into an ID, taking into account fb depth */ - id = pixel[2]>>(8-b) | pixel[1]<>(8-g) | pixel[0]<<(g+b)>>(8-r); + id = _clutter_pix_to_id (pixel); return clutter_get_actor_by_gid (id); } @@ -348,7 +346,10 @@ clutter_main (void) loop = g_main_loop_new (NULL, TRUE); main_loops = g_slist_prepend (main_loops, loop); -#ifdef HAVE_CLUTTER_FRUITY_FOO +#ifdef HAVE_CLUTTER_FRUITY + /* clutter fruity creates an application that forwards events and manually + * spins the mainloop + */ clutter_fruity_main (); #else if (g_main_loop_is_running (main_loops->data))