Give a chance to effects for running when picking

Some effects can change the actor's shape and position, so they need
to run when picking.

https://bugzilla.gnome.org/show_bug.cgi?id=651700
This commit is contained in:
Tomeu Vizoso 2011-06-02 14:16:23 +02:00 committed by Emmanuele Bassi
parent 700c543850
commit 0ede622f51
5 changed files with 269 additions and 121 deletions

View File

@ -2865,6 +2865,9 @@ clutter_actor_paint (ClutterActor *self)
applications to notify when the value of the applications to notify when the value of the
has_overlaps virtual changes. */ has_overlaps virtual changes. */
add_or_remove_flatten_effect (self); add_or_remove_flatten_effect (self);
}
else
CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
/* We save the current paint volume so that the next time the /* We save the current paint volume so that the next time the
* actor queues a redraw we can constrain the redraw to just * actor queues a redraw we can constrain the redraw to just
@ -2922,21 +2925,6 @@ clutter_actor_paint (ClutterActor *self)
if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES)) if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES))
_clutter_actor_draw_paint_volume (self); _clutter_actor_draw_paint_volume (self);
}
else
{
ClutterColor col = { 0, };
CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
_clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
/* Actor will then paint silhouette of itself in supplied
* color. See clutter_stage_get_actor_at_pos() for where
* picking is enabled.
*/
g_signal_emit (self, actor_signals[PICK], 0, &col);
}
done: done:
if (clip_set) if (clip_set)
@ -2980,11 +2968,26 @@ clutter_actor_continue_paint (ClutterActor *self)
/* If this has come from the last effect then we'll just paint the /* If this has come from the last effect then we'll just paint the
actual actor */ actual actor */
if (priv->next_effect_to_paint == NULL) if (priv->next_effect_to_paint == NULL)
{
if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
{ {
priv->propagated_one_redraw = FALSE; priv->propagated_one_redraw = FALSE;
g_signal_emit (self, actor_signals[PAINT], 0); g_signal_emit (self, actor_signals[PAINT], 0);
} }
else
{
ClutterColor col = { 0, };
_clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
/* Actor will then paint silhouette of itself in supplied
* color. See clutter_stage_get_actor_at_pos() for where
* picking is enabled.
*/
g_signal_emit (self, actor_signals[PICK], 0, &col);
}
}
else else
{ {
ClutterEffect *old_current_effect; ClutterEffect *old_current_effect;
@ -2997,19 +3000,31 @@ clutter_actor_continue_paint (ClutterActor *self)
priv->current_effect = priv->next_effect_to_paint->data; priv->current_effect = priv->next_effect_to_paint->data;
priv->next_effect_to_paint = priv->next_effect_to_paint->next; priv->next_effect_to_paint = priv->next_effect_to_paint->next;
if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
{
if (priv->propagated_one_redraw) if (priv->propagated_one_redraw)
{ {
/* If there's an effect queued with this redraw then all /* If there's an effect queued with this redraw then all
effects up to that one will be considered dirty. It is effects up to that one will be considered dirty. It
expected the queued effect will paint the cached image is expected the queued effect will paint the cached
and not call clutter_actor_continue_paint again (although image and not call clutter_actor_continue_paint again
it should work ok if it does) */ (although it should work ok if it does) */
if (priv->effect_to_redraw == NULL || if (priv->effect_to_redraw == NULL ||
priv->current_effect != priv->effect_to_redraw) priv->current_effect != priv->effect_to_redraw)
run_flags |= CLUTTER_EFFECT_RUN_ACTOR_DIRTY; run_flags |= CLUTTER_EFFECT_RUN_ACTOR_DIRTY;
} }
_clutter_effect_paint (priv->current_effect, run_flags); _clutter_effect_paint (priv->current_effect, run_flags);
}
else
{
/* We can't determine when an actor has been modified since
its last pick so lets just assume it has always been
modified */
run_flags |= CLUTTER_EFFECT_RUN_ACTOR_DIRTY;
_clutter_effect_pick (priv->current_effect, run_flags);
}
priv->current_effect = old_current_effect; priv->current_effect = old_current_effect;
} }

View File

@ -11,6 +11,8 @@ gboolean _clutter_effect_get_paint_volume (ClutterEffect *eff
ClutterPaintVolume *volume); ClutterPaintVolume *volume);
void _clutter_effect_paint (ClutterEffect *effect, void _clutter_effect_paint (ClutterEffect *effect,
ClutterEffectRunFlags flags); ClutterEffectRunFlags flags);
void _clutter_effect_pick (ClutterEffect *effect,
ClutterEffectRunFlags flags);
G_END_DECLS G_END_DECLS

View File

@ -248,6 +248,17 @@ clutter_effect_real_paint (ClutterEffect *effect,
_clutter_effect_post_paint (effect); _clutter_effect_post_paint (effect);
} }
static void
clutter_effect_real_pick (ClutterEffect *effect,
ClutterEffectRunFlags flags)
{
ClutterActorMeta *actor_meta = CLUTTER_ACTOR_META (effect);
ClutterActor *actor;
actor = clutter_actor_meta_get_actor (actor_meta);
clutter_actor_continue_paint (actor);
}
static void static void
clutter_effect_notify (GObject *gobject, clutter_effect_notify (GObject *gobject,
GParamSpec *pspec) GParamSpec *pspec)
@ -276,6 +287,7 @@ clutter_effect_class_init (ClutterEffectClass *klass)
klass->post_paint = clutter_effect_real_post_paint; klass->post_paint = clutter_effect_real_post_paint;
klass->get_paint_volume = clutter_effect_real_get_paint_volume; klass->get_paint_volume = clutter_effect_real_get_paint_volume;
klass->paint = clutter_effect_real_paint; klass->paint = clutter_effect_real_paint;
klass->pick = clutter_effect_real_pick;
} }
static void static void
@ -308,6 +320,15 @@ _clutter_effect_paint (ClutterEffect *effect,
CLUTTER_EFFECT_GET_CLASS (effect)->paint (effect, flags); CLUTTER_EFFECT_GET_CLASS (effect)->paint (effect, flags);
} }
void
_clutter_effect_pick (ClutterEffect *effect,
ClutterEffectRunFlags flags)
{
g_return_if_fail (CLUTTER_IS_EFFECT (effect));
CLUTTER_EFFECT_GET_CLASS (effect)->pick (effect, flags);
}
gboolean gboolean
_clutter_effect_get_paint_volume (ClutterEffect *effect, _clutter_effect_get_paint_volume (ClutterEffect *effect,
ClutterPaintVolume *volume) ClutterPaintVolume *volume)

View File

@ -49,7 +49,7 @@ typedef struct _ClutterEffectClass ClutterEffectClass;
* should call clutter_actor_continue_paint() to chain to the next * should call clutter_actor_continue_paint() to chain to the next
* effect and can not cache any results from a previous paint. * effect and can not cache any results from a previous paint.
* *
* Flags passed to the run method of #ClutterEffect. * Flags passed to the paint or pick method of #ClutterEffect.
*/ */
typedef enum typedef enum
{ {
@ -96,8 +96,10 @@ struct _ClutterEffectClass
void (* paint) (ClutterEffect *effect, void (* paint) (ClutterEffect *effect,
ClutterEffectRunFlags flags); ClutterEffectRunFlags flags);
void (* pick) (ClutterEffect *effect,
ClutterEffectRunFlags flags);
/*< private >*/ /*< private >*/
void (* _clutter_effect3) (void);
void (* _clutter_effect4) (void); void (* _clutter_effect4) (void);
void (* _clutter_effect5) (void); void (* _clutter_effect5) (void);
void (* _clutter_effect6) (void); void (* _clutter_effect6) (void);

View File

@ -6,6 +6,7 @@
#define STAGE_HEIGHT 480 #define STAGE_HEIGHT 480
#define ACTORS_X 12 #define ACTORS_X 12
#define ACTORS_Y 16 #define ACTORS_Y 16
#define SHIFT_STEP STAGE_WIDTH / ACTORS_X
typedef struct _State State; typedef struct _State State;
@ -18,6 +19,75 @@ struct _State
gboolean pass; gboolean pass;
}; };
struct _ShiftEffect
{
ClutterShaderEffect parent_instance;
};
struct _ShiftEffectClass
{
ClutterShaderEffectClass parent_class;
};
typedef struct _ShiftEffect ShiftEffect;
typedef struct _ShiftEffectClass ShiftEffectClass;
#define TYPE_SHIFT_EFFECT (shift_effect_get_type ())
G_DEFINE_TYPE (ShiftEffect,
shift_effect,
CLUTTER_TYPE_SHADER_EFFECT);
static void
shader_paint (ClutterEffect *effect,
ClutterEffectRunFlags flags)
{
ClutterShaderEffect *shader = CLUTTER_SHADER_EFFECT (effect);
float tex_width;
ClutterActor *actor =
clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
g_debug ("shader_paint");
clutter_shader_effect_set_shader_source (shader,
"uniform sampler2D tex;\n"
"uniform float step;\n"
"void main (void)\n"
"{\n"
" gl_FragColor = texture2D(tex, vec2 (gl_TexCoord[0].s + step,\n"
" gl_TexCoord[0].t));\n"
"}\n");
tex_width = clutter_actor_get_width (actor);
clutter_shader_effect_set_uniform (shader, "tex", G_TYPE_INT, 1, 0);
clutter_shader_effect_set_uniform (shader, "step", G_TYPE_FLOAT, 1,
SHIFT_STEP / tex_width);
CLUTTER_EFFECT_CLASS (shift_effect_parent_class)->paint (effect, flags);
}
static void
shader_pick (ClutterEffect *effect,
ClutterEffectRunFlags flags)
{
shader_paint (effect, flags);
}
static void
shift_effect_class_init (ShiftEffectClass *klass)
{
ClutterEffectClass *shader_class = CLUTTER_EFFECT_CLASS (klass);
shader_class->paint = shader_paint;
shader_class->pick = shader_pick;
}
static void
shift_effect_init (ShiftEffect *self)
{
}
static gboolean static gboolean
on_timeout (State *state) on_timeout (State *state)
{ {
@ -34,7 +104,7 @@ on_timeout (State *state)
clutter_stage_get_actor_at_pos (CLUTTER_STAGE (state->stage), clutter_stage_get_actor_at_pos (CLUTTER_STAGE (state->stage),
CLUTTER_PICK_REACTIVE, 10, 10); CLUTTER_PICK_REACTIVE, 10, 10);
for (test_num = 0; test_num < 3; test_num++) for (test_num = 0; test_num < 5; test_num++)
{ {
if (test_num == 0) if (test_num == 0)
{ {
@ -69,16 +139,53 @@ on_timeout (State *state)
if (g_test_verbose ()) if (g_test_verbose ())
g_print ("Clipped covering actor:\n"); g_print ("Clipped covering actor:\n");
} }
else if (test_num == 3)
{
clutter_actor_hide (over_actor);
clutter_actor_add_effect_with_name (CLUTTER_ACTOR (state->stage),
"blur",
clutter_blur_effect_new ());
if (g_test_verbose ())
g_print ("With blur effect:\n");
}
else if (test_num == 4)
{
clutter_actor_hide (over_actor);
clutter_actor_remove_effect_by_name (CLUTTER_ACTOR (state->stage),
"blur");
clutter_actor_add_effect_with_name (CLUTTER_ACTOR (state->stage),
"shift",
g_object_new (TYPE_SHIFT_EFFECT, NULL));
if (g_test_verbose ())
g_print ("With shift effect:\n");
}
for (y = 0; y < ACTORS_Y; y++) for (y = 0; y < ACTORS_Y; y++)
for (x = 0; x < ACTORS_X; x++) {
if (test_num == 4)
x = 1;
else
x = 0;
for (; x < ACTORS_X; x++)
{ {
gboolean pass = FALSE; gboolean pass = FALSE;
ClutterActor *actor gfloat pick_x;
ClutterActor *actor;
pick_x = x * state->actor_width + state->actor_width / 2;
if (test_num == 4)
pick_x -= SHIFT_STEP;
actor
= clutter_stage_get_actor_at_pos (CLUTTER_STAGE (state->stage), = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (state->stage),
CLUTTER_PICK_ALL, CLUTTER_PICK_ALL,
x * state->actor_width pick_x,
+ state->actor_width / 2,
y * state->actor_height y * state->actor_height
+ state->actor_height / 2); + state->actor_height / 2);
@ -117,6 +224,7 @@ on_timeout (State *state)
state->pass = FALSE; state->pass = FALSE;
} }
} }
}
clutter_main_quit (); clutter_main_quit ();