[clutter/wip/correct-opacity: 4/9] clutter-actor: Add _clutter_actor_queue_redraw_with_effect



commit b6507bb6ea3b9789e84a83153830454b75b22ab7
Author: Neil Roberts <neil linux intel com>
Date:   Mon Feb 28 12:16:55 2011 +0000

    clutter-actor: Add _clutter_actor_queue_redraw_with_effect
    
    This adds an internal function to queue a redraw from a particular
    effect. If nothing else queues a redraw then when the actor is painted
    the effect will be run without the CLUTTER_EFFECT_RUN_ACTOR_DIRTY
    flag. This allows parametrised offscreen effects to report that they
    need to redraw the image without having to redraw the underlying
    actor. This will be used to implement the 'transparency' effect of
    ClutterActor.
    
    If multiple redraws are queued with different effects then redrawing
    is started from the one that occurs last in the list of effects.

 clutter/clutter-actor-private.h |    6 ++
 clutter/clutter-actor.c         |  126 +++++++++++++++++++++++++++++++++++---
 2 files changed, 122 insertions(+), 10 deletions(-)
---
diff --git a/clutter/clutter-actor-private.h b/clutter/clutter-actor-private.h
index 4d79589..b0797dd 100644
--- a/clutter/clutter-actor-private.h
+++ b/clutter/clutter-actor-private.h
@@ -24,6 +24,7 @@
 
 #include <clutter/clutter-actor.h>
 #include <clutter/clutter-paint-volume-private.h>
+#include <clutter/clutter-effect.h>
 
 G_BEGIN_DECLS
 
@@ -168,6 +169,11 @@ void _clutter_actor_queue_redraw_with_clip   (ClutterActor              *self,
                                               ClutterRedrawFlags         flags,
                                               ClutterPaintVolume        *clip_volume);
 
+void _clutter_actor_queue_redraw_with_effect (ClutterActor              *self,
+                                              ClutterRedrawFlags         flags,
+                                              ClutterPaintVolume        *clip_volume,
+                                              ClutterEffect             *effect);
+
 void _clutter_actor_finish_queue_redraw       (ClutterActor             *self);
 
 ClutterActorRedrawState *_clutter_actor_get_redraw_state (ClutterActor *self);
diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c
index 26be357..3c2284f 100644
--- a/clutter/clutter-actor.c
+++ b/clutter/clutter-actor.c
@@ -461,7 +461,7 @@ struct _ClutterActorPrivate
   ClutterMetaGroup *effects;
 
   /* used when painting, to update the paint volume */
-  ClutterActorMeta *current_effect;
+  ClutterEffect *current_effect;
 
   ClutterPaintVolume paint_volume;
 
@@ -476,6 +476,13 @@ struct _ClutterActorPrivate
      actor is */
   ClutterActorRedrawState redraw_state;
 
+  /* This is used to store an effect which needs to be redrawn. A
+     redraw can be queued to start from a particular effect. This is
+     used by parametrised effects that can cache an image of the
+     actor. If a parameter of the effect changes then it only needs to
+     redraw the cached image, not the actual actor */
+  ClutterEffect *effect_to_redraw;
+
   /* This is used as an out-of-band argument passed to the
      queue-redraw signal so that it can detect when an application
      directly emits the queue-redraw signal without going through the
@@ -1844,7 +1851,7 @@ clutter_actor_real_queue_redraw (ClutterActor *self,
 
   /* If the queue-redraw signal was directly emitted by an application
      or by chaining up from a child actor then we need to clear the
-     clip */
+     clip and the effect */
   if (!priv->from_delayed_queue_redraw)
     {
       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
@@ -1853,6 +1860,8 @@ clutter_actor_real_queue_redraw (ClutterActor *self,
         _clutter_stage_add_dirty_actor (CLUTTER_STAGE (stage),
                                         self,
                                         NULL);
+
+      priv->effect_to_redraw = NULL;
     }
 
   /* If the actor isn't visible, we still had to emit the signal
@@ -2713,7 +2722,7 @@ clutter_actor_continue_paint (ClutterActor *self)
     }
   else
     {
-      ClutterActorMeta *old_current_effect;
+      ClutterEffect *old_current_effect;
       ClutterEffectRunFlags run_flags = 0;
 
       /* Cache the current effect so that we can put it back before
@@ -2724,9 +2733,18 @@ clutter_actor_continue_paint (ClutterActor *self)
       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
 
       if (priv->propagated_one_redraw)
-        run_flags |= CLUTTER_EFFECT_RUN_ACTOR_DIRTY;
+        {
+          /* If there's an effect queued with this redraw then all
+             effects up to that one will be considered dirty. It is
+             expected the queued effect will paint the cached image
+             and not call clutter_actor_continue_paint again (although
+             it should work ok if it does) */
+          if (priv->effect_to_redraw == NULL ||
+              priv->current_effect != priv->effect_to_redraw)
+            run_flags |= CLUTTER_EFFECT_RUN_ACTOR_DIRTY;
+        }
 
-      _clutter_effect_run (CLUTTER_EFFECT (priv->current_effect), run_flags);
+      _clutter_effect_run (priv->current_effect, run_flags);
 
       priv->current_effect = old_current_effect;
     }
@@ -4962,7 +4980,8 @@ _clutter_actor_finish_queue_redraw (ClutterActor *self)
 
   /* Mark the redraw is coming from a delayed queue redraw so that the
      handler can detect when this signal is being directly by an
-     application. In this case it needs to remove any clip */
+     application. In this case it needs to remove any clip and cached
+     effect */
   priv->from_delayed_queue_redraw = TRUE;
 
   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, self);
@@ -5060,9 +5079,12 @@ clutter_actor_queue_redraw (ClutterActor *self)
 
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  _clutter_actor_queue_redraw_with_clip (self,
-                                         0, /* flags */
-                                         NULL /* clip volume (no clip) */);
+  _clutter_actor_queue_redraw_with_effect (self,
+                                           0, /* flags */
+                                           NULL, /* clip volume (no clip) */
+                                           /* null effect means to
+                                              paint the whole actor */
+                                           NULL);
 }
 
 static void
@@ -5133,13 +5155,59 @@ _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
                                        ClutterRedrawFlags  flags,
                                        ClutterPaintVolume *volume)
 {
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+  _clutter_actor_queue_redraw_with_effect (self,
+                                           flags,
+                                           volume,
+                                           NULL /* null effect means
+                                                   to paint the whole
+                                                   actor */);
+}
+
+/*
+ * clutter_actor_queue_redraw_with_clip:
+ * @self: A #ClutterActor
+ * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
+ *   this queue redraw.
+ * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
+ *   redrawn or %NULL if you are just using a @flag to state your
+ *   desired clipping.
+ * @effect: A #ClutterEffect that needs to be painted or %NULL.
+ *
+ * This is the same as clutter_actor_queue_redraw_with_clip() except
+ * that it additionally takes an effect. When @effect is not %NULL,
+ * only the other effects not including the given one will have the
+ * %CLUTTER_EFFECT_RUN_DIRTY_ACTOR flag set and the rest will
+ * not. This gives the effect a chance to draw its cached image
+ * instead of continuing the rest of the paint sequence. This is
+ * useful for offscreen effects that have their own properties which
+ * only affect the appearance of the final rendering of the texture
+ * without affecting the drawing of the actual actor.
+ *
+ * Any other effects that are layered on top of the passed in effect
+ * will still be passed the %CLUTTER_EFFECT_RUN_DIRTY_ACTOR flag. If
+ * anything queues a redraw on the actor without specifying an effect
+ * or with an effect that is lower in the chain of effects then
+ * rendering will take place from that point instead.
+ */
+void
+_clutter_actor_queue_redraw_with_effect (ClutterActor       *self,
+                                         ClutterRedrawFlags  flags,
+                                         ClutterPaintVolume *volume,
+                                         ClutterEffect      *effect)
+{
+  ClutterActorPrivate *priv;
   ClutterPaintVolume allocation_pv;
   ClutterPaintVolume *pv;
   gboolean should_free_pv;
+  gboolean was_dirty;
   ClutterActor *stage;
 
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
+  priv = self->priv;
+
   /* There's no point in queueing a redraw on a destroyed actor */
   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
     return;
@@ -5151,7 +5219,7 @@ _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
 
       /* If the actor doesn't have a valid allocation then we will
        * queue a full stage redraw. */
-      if (self->priv->needs_allocation)
+      if (priv->needs_allocation)
         {
           /* NB: NULL denotes an undefined clip which will result in a
            * full redraw... */
@@ -5184,6 +5252,8 @@ _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
       should_free_pv = FALSE;
     }
 
+  was_dirty = priv->redraw_state.is_dirty;
+
   /* Ignore queuing a redraw for actors not descended from a stage */
   stage = _clutter_actor_get_stage_internal (self);
 
@@ -5195,6 +5265,42 @@ _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
 
   if (should_free_pv)
     clutter_paint_volume_free (pv);
+
+  /* If this is the first redraw queued then we can directly use the
+     effectparameter */
+  if (!was_dirty)
+    priv->effect_to_redraw = effect;
+  /* Otherwise we need to merge it with the existing effect parameter */
+  else if (effect)
+    {
+      /* If there's already an effect then we need to use whichever is
+         later in the chain of actors. Otherwise a full redraw has
+         already been queued on the actor so we need to ignore the
+         effect parameter */
+      if (priv->effect_to_redraw)
+        {
+          if (priv->effects == NULL)
+            g_warning ("Redraw queued with an effect that is "
+                       "not applied to the actor");
+          else
+            {
+              const GList *l;
+
+              for (l = _clutter_meta_group_peek_metas (priv->effects);
+                   l != NULL;
+                   l = l->next)
+                {
+                  if (l->data == priv->effect_to_redraw ||
+                      l->data == effect)
+                    priv->effect_to_redraw = l->data;
+                }
+            }
+        }
+    }
+  else
+    /* If no effect is specified then we need to redraw the whole
+       actor */
+    priv->effect_to_redraw = NULL;
 }
 
 const ClutterActorBox *



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]