From: Emmanuele Bassi Date: Tue, 27 Jan 2009 16:12:30 +0000 (+0000) Subject: Merge branch 'generic-actor-clone' X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3cfc7fb1ca428c73ff2434f178cb8cc4e01728d4;p=profile%2Fivi%2Fclutter.git Merge branch 'generic-actor-clone' * generic-actor-clone: Remove CloneTexture from the API [tests] Clean up the Clone interactive test Rename ActorClone to Clone/2 Rename ActorClone to Clone/1 Improves the unit test to verify more awkward scaling and some corresponding fixes Implements a generic ClutterActorClone that doesn't need fbos. --- 3cfc7fb1ca428c73ff2434f178cb8cc4e01728d4 diff --cc clutter/clutter-actor.c index 9d8df31,53ffac0..c4a9577 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@@ -7787,3 -7713,26 +7797,26 @@@ clutter_actor_create_pango_context (Clu return retval; } + + /* Allows overriding the parent traversed when querying an actors paint - * opacity. Used by ClutterActorClone. */ ++ * opacity. Used by ClutterClone. */ + void + _clutter_actor_set_opacity_parent (ClutterActor *self, + ClutterActor *parent) + { + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + self->priv->opacity_parent = parent; + } + + /* Allows you to disable applying the actors model view transform during - * a paint. Used by ClutterActorClone. */ ++ * a paint. Used by ClutterClone. */ + void + _clutter_actor_set_enable_model_view_transform (ClutterActor *self, + gboolean enable) + { + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + self->priv->enable_model_view_transform = enable; + } + diff --cc clutter/clutter-clone.c index 0000000,daeec15..0f76b4d mode 000000,100644..100644 --- a/clutter/clutter-clone.c +++ b/clutter/clutter-clone.c @@@ -1,0 -1,326 +1,325 @@@ + /* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2008 Intel Corporation. + * + * Authored By: Robert Bragg + * + * 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 . + */ + + /** + * SECTION:clutterclone + * @short_description: An actor that displays a clone of a source actor + * + * #ClutterClone is a #ClutterActor which draws with the paint + * function of another actor, scaled to fit its own allocation. + * + * #ClutterClone can be used to efficiently clone any other actor. + * + * This is different from clutter_texture_new_from_actor() + * which requires support for FBOs in the underlying GL + * implementation. + * + * #ClutterClone is available since Clutter 1.0 + */ + + #ifdef HAVE_CONFIG_H + #include "config.h" + #endif + + #include "clutter-color.h" + #include "clutter-clone.h" + #include "clutter-debug.h" + #include "clutter-main.h" + #include "clutter-private.h" + + #include "cogl/cogl.h" + + G_DEFINE_TYPE (ClutterClone, clutter_clone, CLUTTER_TYPE_ACTOR); + + enum + { + PROP_0, + + PROP_SOURCE + }; + + #define CLUTTER_CLONE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_CLONE, ClutterClonePrivate)) + + struct _ClutterClonePrivate + { + ClutterActor *clone_source; + }; + + static void + clutter_clone_get_preferred_width (ClutterActor *self, + ClutterUnit for_height, + ClutterUnit *min_width_p, + ClutterUnit *natural_width_p) + { + ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv; + ClutterActor *clone_source = priv->clone_source; + + if (G_UNLIKELY (clone_source == NULL)) + { + if (min_width_p) + *min_width_p = 0; + + if (natural_width_p) + *natural_width_p = 0; + } + else + clutter_actor_get_preferred_width (clone_source, + for_height, + min_width_p, + natural_width_p); + } + + static void + clutter_clone_get_preferred_height (ClutterActor *self, + ClutterUnit for_width, + ClutterUnit *min_height_p, + ClutterUnit *natural_height_p) + { + ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv; + ClutterActor *clone_source = priv->clone_source; + + if (G_UNLIKELY (clone_source == NULL)) + { + if (min_height_p) + *min_height_p = 0; + + if (natural_height_p) + *natural_height_p = 0; + } + else + clutter_actor_get_preferred_height (clone_source, + for_width, + min_height_p, + natural_height_p); + } + + static void + clutter_clone_paint (ClutterActor *self) + { + ClutterClone *clone = CLUTTER_CLONE (self); + ClutterClonePrivate *priv = clone->priv; + ClutterGeometry geom; + ClutterGeometry clone_source_geom; + gfloat x_scale, y_scale; + + if (G_UNLIKELY (priv->clone_source == NULL)) + return; + + CLUTTER_NOTE (PAINT, + "painting clone actor '%s'", + clutter_actor_get_name (self) ? clutter_actor_get_name (self) + : "unknown"); + + clutter_actor_get_allocation_geometry (self, &geom); + clutter_actor_get_allocation_geometry (priv->clone_source, + &clone_source_geom); + + /* We need to scale what the clone-source actor paints to fill our own + * allocation... */ + + x_scale = (gfloat) geom.width / clone_source_geom.width; + y_scale = (gfloat) geom.height / clone_source_geom.height; + - cogl_scale (COGL_FIXED_FROM_FLOAT (x_scale), - COGL_FIXED_FROM_FLOAT (y_scale)); ++ cogl_scale (x_scale, y_scale, 1.0); + + /* The final bits of magic: + * - We need to make sure that when the clone-source actor's paint method + * calls clutter_actor_get_paint_opacity, it traverses our parent not it's + * real parent. + * - We need to stop clutter_actor_paint applying the model view matrix of + * the clone source actor. + */ + _clutter_actor_set_opacity_parent (priv->clone_source, + clutter_actor_get_parent (self)); + _clutter_actor_set_enable_model_view_transform (priv->clone_source, FALSE); + + clutter_actor_paint (priv->clone_source); + + _clutter_actor_set_enable_model_view_transform (priv->clone_source, TRUE); + _clutter_actor_set_opacity_parent (priv->clone_source, NULL); + } + + static void + clutter_clone_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) + { + ClutterClone *clone = CLUTTER_CLONE (gobject); + + switch (prop_id) + { + case PROP_SOURCE: + clutter_clone_set_source (clone, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } + } + + static void + clutter_clone_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) + { + ClutterClonePrivate *priv = CLUTTER_CLONE (gobject)->priv; + + switch (prop_id) + { + case PROP_SOURCE: + g_value_set_object (value, priv->clone_source); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } + } + + static void + clutter_clone_dispose (GObject *gobject) + { + ClutterClonePrivate *priv = CLUTTER_CLONE (gobject)->priv; + + if (priv->clone_source) + { + g_object_unref (priv->clone_source); + priv->clone_source = NULL; + } + + G_OBJECT_CLASS (clutter_clone_parent_class)->dispose (gobject); + } + + static void + clutter_clone_class_init (ClutterCloneClass *klass) + { + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + GParamSpec *pspec = NULL; + + g_type_class_add_private (gobject_class, sizeof (ClutterClonePrivate)); + + actor_class->paint = clutter_clone_paint; + actor_class->get_preferred_width = clutter_clone_get_preferred_width; + actor_class->get_preferred_height = clutter_clone_get_preferred_height; + + gobject_class->dispose = clutter_clone_dispose; + gobject_class->set_property = clutter_clone_set_property; + gobject_class->get_property = clutter_clone_get_property; + + /** + * ClutterClone:source: + * + * This property specifies the source actor being cloned. + * + * Since: 1.0 + */ + pspec = g_param_spec_object ("source", + "Source", + "Specifies the actor to be cloned", + CLUTTER_TYPE_ACTOR, + G_PARAM_CONSTRUCT_ONLY | + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_SOURCE, pspec); + } + + static void + clutter_clone_init (ClutterClone *self) + { + ClutterClonePrivate *priv; + + self->priv = priv = CLUTTER_CLONE_GET_PRIVATE (self); + + priv->clone_source = NULL; + } + + /** + * clutter_clone_new: + * @source: a #ClutterActor, or %NULL + * + * Creates a new #ClutterActor which clones @source/ + * + * Return value: the newly created #ClutterClone + * + * Since: 1.0 + */ + ClutterActor * + clutter_clone_new (ClutterActor *source) + { + return g_object_new (CLUTTER_TYPE_CLONE, "source", source, NULL); + } + + /** + * clutter_clone_set_source: + * @clone: a #ClutterClone + * @source: a #ClutterActor, or %NULL + * + * Sets @source as the source actor to be cloned by @clone. + * + * Since: 1.0 + */ + void + clutter_clone_set_source (ClutterClone *clone, + ClutterActor *source) + { + ClutterClonePrivate *priv; + + g_return_if_fail (CLUTTER_IS_CLONE (clone)); + g_return_if_fail (source == NULL || CLUTTER_IS_ACTOR (source)); + + priv = clone->priv; + + if (priv->clone_source) + { + g_object_unref (priv->clone_source); + priv->clone_source = NULL; + } + + if (source) + priv->clone_source = g_object_ref (source); + + g_object_notify (G_OBJECT (clone), "source"); + + clutter_actor_queue_relayout (CLUTTER_ACTOR (clone)); + } + + /** + * clutter_clone_get_source: + * @clone: a #ClutterClone + * + * Retrieves the source #ClutterActor being cloned by @clone + * + * Return value: the actor source for the clone + * + * Since: 1.0 + */ + ClutterActor * + clutter_clone_get_clone_source (ClutterClone *clone) + { + g_return_val_if_fail (CLUTTER_IS_CLONE (clone), NULL); + + return clone->priv->clone_source; + } diff --cc tests/interactive/test-actor-clone.c index 0000000,17f01d5..fc595ab mode 000000,100644..100644 --- a/tests/interactive/test-actor-clone.c +++ b/tests/interactive/test-actor-clone.c @@@ -1,0 -1,279 +1,288 @@@ + #include + + #include + #include + #include + #include + #include + + #define NHANDS 6 + + typedef struct SuperOH + { + ClutterActor **hand, *bgtex; + ClutterActor *real_hand; + ClutterActor *group; + ClutterActor *stage; + + gint stage_width; + gint stage_height; + gfloat radius; + + ClutterBehaviour *scaler_1; + ClutterBehaviour *scaler_2; + ClutterTimeline *timeline; + } 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 } + }; + + /* input handler */ + static gboolean + input_cb (ClutterActor *stage, + ClutterEvent *event, + gpointer data) + { + SuperOH *oh = data; + + if (event->type == CLUTTER_BUTTON_PRESS) + { + 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) at %d, %d ***\n", + button_event->button, + x, y); + + e = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (stage), x, y); + + /* only allow hiding the clones */ + if (e && CLUTTER_IS_CLONE (e)) + { + clutter_actor_hide (e); + return TRUE; + } + } + else if (event->type == CLUTTER_KEY_RELEASE) + { + ClutterKeyEvent *kev = (ClutterKeyEvent *) event; + + g_print ("*** key press event (key:%c) ***\n", + clutter_key_event_symbol (kev)); + + if (clutter_key_event_symbol (kev) == CLUTTER_q) + { + clutter_main_quit (); + return TRUE; + } + else if (clutter_key_event_symbol (kev) == CLUTTER_r) + { + gint i; + + for (i = 0; i < n_hands; i++) + clutter_actor_show (oh->hand[i]); + + clutter_actor_show (oh->real_hand); + + return TRUE; + } + } + + return FALSE; + } + + + /* Timeline handler */ + static void + frame_cb (ClutterTimeline *timeline, + gint frame_num, + gpointer data) + { + SuperOH *oh = data; + gint i; + + /* Rotate everything clockwise about stage center*/ + + clutter_actor_set_rotation (oh->group, + CLUTTER_Z_AXIS, + frame_num, + oh->stage_width / 2, + oh->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. + */ + clutter_actor_set_rotation (oh->hand[i], + CLUTTER_Z_AXIS, + -6.0 * frame_num, + 0, 0, 0); + } + } + ++static gdouble ++my_sine_wave (ClutterAlpha *alpha, ++ gpointer dummy G_GNUC_UNUSED) ++{ ++ ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha); ++ gdouble progress = clutter_timeline_get_progress (timeline); ++ ++ return sin (progress * G_PI); ++} ++ + G_MODULE_EXPORT int + test_actor_clone_main (int argc, char *argv[]) + { + ClutterAlpha *alpha; + ClutterActor *stage; + ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff }; + SuperOH *oh; + gint i; + GError *error; + ClutterActor *real_hand, *tmp; + ClutterColor clr = { 0xff, 0xff, 0x00, 0xff }; + + error = NULL; + + 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); + + return EXIT_FAILURE; + } + + stage = clutter_stage_get_default (); + clutter_actor_set_size (stage, 800, 600); + + clutter_stage_set_title (CLUTTER_STAGE (stage), "Clone Test"); + clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); + + oh = g_new (SuperOH, 1); + + /* Create a timeline to manage animation */ + oh->timeline = clutter_timeline_new (360, 60); + clutter_timeline_set_loop (oh->timeline, TRUE); + + /* fire a callback for frame change */ + g_signal_connect (oh->timeline, "new-frame", G_CALLBACK (frame_cb), oh); + + /* Set up some behaviours to handle scaling */ - alpha = clutter_alpha_new_with_func (oh->timeline, clutter_sine_func, - NULL, NULL); ++ alpha = clutter_alpha_new_with_func (oh->timeline, my_sine_wave, NULL, NULL); + + oh->scaler_1 = clutter_behaviour_scale_new (alpha, 0.5, 0.5, 1.0, 1.0); + oh->scaler_2 = clutter_behaviour_scale_new (alpha, 1.0, 1.0, 0.5, 0.5); + + tmp = clutter_texture_new_from_file ("redhand.png", &error); + if (tmp == NULL) + { + g_error ("image load failed: %s", error->message); + return EXIT_FAILURE; + } + + clutter_actor_set_size (tmp, 300, 500); + + real_hand = clutter_group_new (); + clutter_container_add_actor (CLUTTER_CONTAINER (real_hand), tmp); + tmp = clutter_rectangle_new_with_color (&clr); + clutter_actor_set_size (tmp, 100, 100); + clutter_container_add_actor (CLUTTER_CONTAINER (real_hand), tmp); + clutter_actor_set_scale (real_hand, 0.5, 0.5); + oh->real_hand = real_hand; + + /* Now stick the group we want to clone into another group with a custom + * opacity to verify that the clones don't traverse this parent when + * calculating their opacity. */ + tmp = clutter_group_new (); + clutter_actor_set_opacity (tmp, 0x80); + clutter_container_add_actor (CLUTTER_CONTAINER (tmp), real_hand); + clutter_container_add_actor (CLUTTER_CONTAINER (stage), tmp); + + /* create a new group to hold multiple actors in a group */ + oh->group = clutter_group_new(); + + oh->hand = g_new (ClutterActor*, n_hands); + + oh->stage_width = clutter_actor_get_width (stage); + oh->stage_height = clutter_actor_get_height (stage); + oh->radius = (oh->stage_width + oh->stage_height) + / n_hands; + + for (i = 0; i < n_hands; i++) + { + gint x, y, w, h; + + /* Create a texture from file, then clone in to same resources */ + oh->hand[i] = clutter_clone_new (real_hand); + clutter_actor_set_size (oh->hand[i], 200, 213); + + /* Place around a circle */ + w = clutter_actor_get_width (oh->hand[0]); + h = clutter_actor_get_height (oh->hand[0]); + + x = oh->stage_width / 2 + + oh->radius + * cos (i * G_PI / (n_hands / 2)) + - w / 2; + + y = oh->stage_height / 2 + + oh->radius + * sin (i * G_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 (i % 2) + clutter_behaviour_apply (oh->scaler_1, oh->hand[i]); + else + clutter_behaviour_apply (oh->scaler_2, oh->hand[i]); + } + + /* Add the group to the stage */ + clutter_container_add_actor (CLUTTER_CONTAINER (stage), oh->group); + + /* Show everying */ + clutter_actor_show (stage); + + 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 (oh->timeline); + + clutter_main (); + + /* clean up */ + g_object_unref (oh->scaler_1); + g_object_unref (oh->scaler_2); + g_object_unref (oh->timeline); + g_free (oh->hand); + g_free (oh); + + return EXIT_SUCCESS; + } diff --cc tests/interactive/test-actors.c index 819adfa,f1edacd..403931f --- a/tests/interactive/test-actors.c +++ b/tests/interactive/test-actors.c @@@ -164,29 -153,32 +163,31 @@@ test_actors_main (int argc, char *argv[ stage = clutter_stage_get_default (); clutter_actor_set_size (stage, 800, 600); - clutter_stage_set_title (CLUTTER_STAGE (stage), "Actors Test"); - clutter_stage_set_color (CLUTTER_STAGE (stage), - &stage_color); + clutter_stage_set_title (CLUTTER_STAGE (stage), "Clone Test"); + clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); - oh = g_new(SuperOH, 1); + oh = g_new (SuperOH, 1); + oh->stage = stage; /* 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 */ + oh->timeline = clutter_timeline_new (360, 60); + clutter_timeline_set_loop (oh->timeline, TRUE); /* fire a callback for frame change */ - g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), oh); + g_signal_connect (oh->timeline, "new-frame", G_CALLBACK (frame_cb), oh); /* Set up some behaviours to handle scaling */ - alpha = clutter_alpha_new_with_func (timeline, my_sine_wave, NULL, NULL); - alpha = clutter_alpha_new_with_func (oh->timeline, clutter_sine_func, - NULL, NULL); ++ alpha = clutter_alpha_new_with_func (oh->timeline, my_sine_wave, NULL, NULL); - scaler_1 = clutter_behaviour_scale_new (alpha, - 0.5, 0.5, - 1.0, 1.0); + oh->scaler_1 = clutter_behaviour_scale_new (alpha, 0.5, 0.5, 1.0, 1.0); + oh->scaler_2 = clutter_behaviour_scale_new (alpha, 1.0, 1.0, 0.5, 0.5); - scaler_2 = clutter_behaviour_scale_new (alpha, - 1.0, 1.0, - 0.5, 0.5); + real_hand = clutter_texture_new_from_file ("redhand.png", &error); + if (real_hand == NULL) + { + g_error ("image load failed: %s", error->message); + return EXIT_FAILURE; + } /* create a new group to hold multiple actors in a group */ oh->group = clutter_group_new();