diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 298d8ec97..5fc30fe5f 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -1171,7 +1171,7 @@ clutter_stage_read_pixels (ClutterStage *stage, g_return_val_if_fail (x >= 0 && y >= 0, NULL); /* Force a redraw of the stage before reading back pixels */ - clutter_stage_paint (CLUTTER_ACTOR (stage)); + clutter_redraw (stage); clutter_stage_ensure_current (stage); glGetIntegerv (GL_VIEWPORT, viewport); @@ -1191,6 +1191,21 @@ clutter_stage_read_pixels (ClutterStage *stage, pixels = g_malloc (height * rowstride); temprow = g_malloc (rowstride); + /* Setup the pixel store parameters that may have been changed by + Cogl */ + glPixelStorei (GL_PACK_ALIGNMENT, 4); +#ifdef HAVE_COGL_GL + glPixelStorei (GL_PACK_ROW_LENGTH, 0); + glPixelStorei (GL_PACK_SKIP_PIXELS, 0); + glPixelStorei (GL_PACK_SKIP_ROWS, 0); +#endif /* HAVE_COGL_GL */ + + /* The y co-ordinate should be given in OpenGL's coordinate system + so 0 is the bottom row */ + y = stage_height - 1 - y - height; + + glFinish (); + /* check whether we need to read into a smaller temporary buffer */ glReadPixels (x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); diff --git a/tests/test-stage-read-pixels.c b/tests/test-stage-read-pixels.c index e063ab3cb..89e78d79d 100644 --- a/tests/test-stage-read-pixels.c +++ b/tests/test-stage-read-pixels.c @@ -1,290 +1,155 @@ #include +#include -#if defined (_MSC_VER) && !defined (_USE_MATH_DEFINES) -#define _USE_MATH_DEFINES -#endif +#define DOT_SIZE 2 +#define TEX_SIZE 64 -#include -#include -#include -#include +typedef struct _CallbackData CallbackData; -#define TRAILS 0 -#define NHANDS 6 -#define RADIUS ((CLUTTER_STAGE_WIDTH()+CLUTTER_STAGE_HEIGHT())/NHANDS) - -typedef struct SuperOH +struct _CallbackData { - ClutterActor **hand, *bgtex; - ClutterActor *group; - - ClutterActor *stage; - ClutterActor *tv; - -} SuperOH; - -static gint n_hands = NHANDS; - -static GOptionEntry super_oh_entries[] = { - { - "num-hands", 'n', - 0, - G_OPTION_ARG_INT, &n_hands, - "Number of hands", "HANDS" - }, - { NULL } + ClutterActor *stage; + ClutterActor *tex; + ClutterActor *box; + ClutterMotionEvent event; + guint idle_source; }; -static gint -get_radius (void) +static ClutterActor * +make_label (void) { - return (CLUTTER_STAGE_HEIGHT() + CLUTTER_STAGE_HEIGHT()) / n_hands ; + ClutterActor *label; + gchar *text; + gchar *argv[] = { "ls", "--help", NULL }; + + label = clutter_label_new (); + clutter_label_set_font_name (CLUTTER_LABEL (label), "Sans 10"); + + if (g_spawn_sync (NULL, argv, NULL, + G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_SEARCH_PATH, + NULL, NULL, &text, NULL, NULL, NULL)) + { + clutter_label_set_text (CLUTTER_LABEL (label), text); + g_free (text); + } + + return label; } -/* input handler */ -static gboolean -input_cb (ClutterStage *stage, - ClutterEvent *event, - gpointer data) +static ClutterActor * +make_tex (void) { - if (event->type == CLUTTER_BUTTON_PRESS) + ClutterActor *tex = clutter_texture_new (); + + clutter_actor_set_size (tex, TEX_SIZE * 2, TEX_SIZE * 2); + + return tex; +} + +static ClutterActor * +make_box (void) +{ + ClutterActor *box; + static const ClutterColor blue = { 0x00, 0x00, 0xff, 0xff }; + + box = clutter_rectangle_new_with_color (&blue); + clutter_actor_set_size (box, DOT_SIZE + 2, DOT_SIZE + 2); + clutter_actor_hide (box); + + return box; +} + +static gboolean +on_motion_idle (gpointer user_data) +{ + CallbackData *data = (CallbackData *) user_data; + guchar *pixels, *p; + guint stage_width, stage_height; + gint x, y; + + data->idle_source = 0; + + clutter_actor_get_size (data->stage, &stage_width, &stage_height); + + x = CLAMP (data->event.x - TEX_SIZE / 2, 0, (int) stage_width - TEX_SIZE); + y = CLAMP (data->event.y - TEX_SIZE / 2, 0, (int) stage_height - TEX_SIZE); + + clutter_actor_set_position (data->box, x + TEX_SIZE / 2 - 1, + y + TEX_SIZE / 2 - 1); + clutter_actor_show (data->box); + /* Redraw so that the layouting will be done and the box will be + drawn in the right position */ + clutter_redraw (CLUTTER_STAGE (data->stage)); + + pixels = clutter_stage_read_pixels (CLUTTER_STAGE (data->stage), + x, y, TEX_SIZE, TEX_SIZE); + + /* Make a red dot in the center */ + p = pixels + (TEX_SIZE / 2 - DOT_SIZE / 2) * TEX_SIZE * 4 + + (TEX_SIZE / 2 - DOT_SIZE / 2) * 4; + for (y = 0; y < DOT_SIZE; y++) { - ClutterButtonEvent *button_event; - ClutterActor *e; - gint x, y; - - clutter_event_get_coords (event, &x, &y); - - button_event = (ClutterButtonEvent *) event; - g_print ("*** button press event (button:%d) ***\n", - button_event->button); - - e = clutter_stage_get_actor_at_pos (stage, x, y); - - if (e && (CLUTTER_IS_TEXTURE (e) || CLUTTER_IS_CLONE_TEXTURE (e))) - { - clutter_actor_hide (e); - return TRUE; - } + for (x = 0; x < DOT_SIZE; x++) + { + *(p++) = 255; + memset (p, 0, 3); + p += 3; + } + p += TEX_SIZE * 4 - DOT_SIZE * 4; } - else if (event->type == CLUTTER_KEY_RELEASE) - { - ClutterKeyEvent *kev = (ClutterKeyEvent *) event; - g_print ("*** key press event (key:%c) ***\n", - clutter_key_event_symbol (kev)); + /* Set all of the alpa values to full */ + for (p = pixels + TEX_SIZE * TEX_SIZE * 4; p > pixels; p -= 4) + *(p - 1) = 255; - if (clutter_key_event_symbol (kev) == CLUTTER_q) - { - clutter_main_quit (); - return TRUE; - } - } + clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (data->tex), + pixels, TRUE, + TEX_SIZE, TEX_SIZE, + TEX_SIZE * 4, 4, 0, NULL); + g_free (pixels); return FALSE; } -static gboolean update_snapshot (gpointer data) +static gboolean +on_motion (ClutterActor *stage, ClutterMotionEvent *event, CallbackData *data) { - SuperOH *oh = data; - gint width = CLUTTER_STAGE_WIDTH(); - gint height = CLUTTER_STAGE_HEIGHT(); - gint x, y, rowstride; - guchar *pixels; + /* Handle the motion event in an idle handler so that multiple + events will be combined into one */ + if (data->idle_source == 0) + data->idle_source = clutter_threads_add_idle (on_motion_idle, data); - pixels = clutter_stage_read_pixels (CLUTTER_STAGE (oh->stage), 0, 0, width, height); - g_assert (pixels); + data->event = *event; - /* Alpha data is not guaranteed to be sensible and we don't need it, - * overwrite it with full-alpha. - */ - rowstride = width * 4; - for (y = 0; y < height; y++) - for (x = 3; x < rowstride; x += 4) - pixels[(y * rowstride) + x] = 0xff; - - clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (oh->tv), pixels, TRUE, width, height, width *4, - 4, 0, NULL); - g_free (pixels); - return TRUE; + return FALSE; } -/* Timeline handler */ -static void -frame_cb (ClutterTimeline *timeline, - gint frame_num, - gpointer data) -{ - SuperOH *oh = (SuperOH *)data; - gint i; - - /* Rotate everything clockwise about stage center*/ - - clutter_actor_set_rotation (CLUTTER_ACTOR (oh->group), - CLUTTER_Z_AXIS, - frame_num, - CLUTTER_STAGE_WIDTH () / 2, - CLUTTER_STAGE_HEIGHT () / 2, - 0); - - for (i = 0; i < n_hands; i++) - { - gdouble scale_x, scale_y; - - clutter_actor_get_scale (oh->hand[i], &scale_x, &scale_y); - - /* Rotate each hand around there centers - to get this we need - * to take into account any scaling. - * - * FIXME: scaling causes drift so disabled for now. Need rotation - * unit based functions to fix. - */ - clutter_actor_set_rotation (oh->hand[i], CLUTTER_Z_AXIS, - - 6.0 * frame_num, 0, 0, 0); - } - update_snapshot (oh); -} - - int -main (int argc, char *argv[]) +main (int argc, char **argv) { - ClutterTimeline *timeline; - ClutterAlpha *alpha; - ClutterBehaviour *scaler_1, *scaler_2; - ClutterActor *stage; - ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff }; - SuperOH *oh; - gint i; - GError *error; + CallbackData data; - error = NULL; + clutter_init (&argc, &argv); - clutter_init_with_args (&argc, &argv, - NULL, - super_oh_entries, - NULL, - &error); - if (error) - { - g_warning ("Unable to initialise Clutter:\n%s", - error->message); - g_error_free (error); + data.idle_source = 0; + data.stage = clutter_stage_get_default (); - exit (1); - } + data.tex = make_tex (); + data.box = make_box (); + clutter_actor_set_position (data.tex, + clutter_actor_get_width (data.stage) + - clutter_actor_get_width (data.tex), + clutter_actor_get_height (data.stage) + - clutter_actor_get_height (data.tex)); - stage = clutter_stage_get_default (); - clutter_actor_set_size (stage, 800, 600); + clutter_container_add (CLUTTER_CONTAINER (data.stage), + make_label (), data.tex, data.box, NULL); - clutter_stage_set_title (CLUTTER_STAGE (stage), "Actors Test"); - clutter_stage_set_color (CLUTTER_STAGE (stage), - &stage_color); + g_signal_connect (data.stage, "motion-event", G_CALLBACK (on_motion), &data); - oh = g_new(SuperOH, 1); - - /* Create a timeline to manage animation */ - timeline = clutter_timeline_new (360, 60); /* num frames, fps */ - g_object_set (timeline, "loop", TRUE, NULL); /* have it loop */ - - /* fire a callback for frame change */ - g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), oh); - - /* Set up some behaviours to handle scaling */ - alpha = clutter_alpha_new_full (timeline, CLUTTER_ALPHA_SINE, NULL, NULL); - - scaler_1 = clutter_behaviour_scale_new (alpha, - 0.5, 0.5, - 1.0, 1.0); - - scaler_2 = clutter_behaviour_scale_new (alpha, - 1.0, 1.0, - 0.5, 0.5); - - /* create a new group to hold multiple actors in a group */ - oh->group = clutter_group_new(); - - oh->hand = g_new (ClutterActor*, n_hands); - for (i = 0; i < n_hands; i++) - { - gint x, y, w, h; - gint radius = get_radius (); - - /* Create a texture from file, then clone in to same resources */ - if (i == 0) - { - if ((oh->hand[i] = clutter_texture_new_from_file ("redhand.png", - &error)) == NULL) - { - g_error ("image load failed: %s", error->message); - exit (1); - } - } - else - oh->hand[i] = clutter_clone_texture_new (CLUTTER_TEXTURE(oh->hand[0])); - - /* Place around a circle */ - w = clutter_actor_get_width (oh->hand[0]); - h = clutter_actor_get_height (oh->hand[0]); - - x = CLUTTER_STAGE_WIDTH () / 2 - + radius - * cos (i * M_PI / (n_hands / 2)) - - w / 2; - - y = CLUTTER_STAGE_HEIGHT () / 2 - + radius - * sin (i * M_PI / (n_hands / 2)) - - h / 2; - - clutter_actor_set_position (oh->hand[i], x, y); - - clutter_actor_move_anchor_point_from_gravity (oh->hand[i], - CLUTTER_GRAVITY_CENTER); - - /* Add to our group group */ - clutter_container_add_actor (CLUTTER_CONTAINER (oh->group), oh->hand[i]); - -#if 1 /* FIXME: disabled as causes drift? - see comment above */ - if (i % 2) - clutter_behaviour_apply (scaler_1, oh->hand[i]); - else - clutter_behaviour_apply (scaler_2, oh->hand[i]); -#endif - } - - /* Add the group to the stage */ - clutter_container_add_actor (CLUTTER_CONTAINER (stage), - CLUTTER_ACTOR (oh->group)); - - /* Show everying ( and map window ) */ - clutter_actor_show (stage); - - oh->stage = stage; - oh->tv = clutter_texture_new (); - - clutter_container_add_actor (CLUTTER_CONTAINER (stage), - CLUTTER_ACTOR (oh->tv)); - clutter_actor_set_position (oh->tv, CLUTTER_STAGE_WIDTH() * 0.025, CLUTTER_STAGE_HEIGHT() * 0.025); - clutter_actor_set_scale (oh->tv, 0.95, 0.95); - clutter_actor_set_opacity (oh->tv, 0.9 * 0xff); - clutter_actor_show (oh->tv); - clutter_actor_lower_bottom (oh->tv); - - g_signal_connect (stage, "button-press-event", - G_CALLBACK (input_cb), - oh); - g_signal_connect (stage, "key-release-event", - G_CALLBACK (input_cb), - oh); - - /* and start it */ - clutter_timeline_start (timeline); + clutter_actor_show (data.stage); clutter_main (); - g_free (oh->hand); - g_free (oh); - return 0; }