clutter-actor: Add a 'has_overlaps' virtual
This adds a virtual to ClutterActor so that an actor subclass can report whether it has overlapping primitives. ClutterActor uses this to determine whether it needs to use ClutterFlattenEffect to implement the opacity property. The default implementation of the virtual returns TRUE which means that most actors will end up being redirected offscreen when the opacity != 255. ClutterTexture and ClutterRectangle override this to return FALSE because they should never need to be redirected. ClutterClone overrides it to divert to the source. The values for the ClutterOffscreenRedirect enum have changed to: AUTOMATIC_FOR_OPACITY The actor will only be redirected if has_overlaps returns TRUE and the opacity is < 255 ALWAYS_FOR_OPACITY The actor will always be redirected if the opacity < 255 regardless of the return value of has_overlaps ALWAYS The actor will always be redirected offscreen. This means that the property can't be used to prevent the actor from being redirected but only to increase the likelihood that it will be redirected. ClutterActor now adds and removes the flatten effect depending on whether flattening is needed directly in clutter_actor_paint(). There are new internal versions of add/remove_effect that don't queue a redraw. This means that ClutterFlattenEffect is now just a no-op subclass of ClutterOffscreen. It is only needed because ClutterOffscreen is abstract. Removing the effect also makes it so that the cached image will be freed as soon as an actor is repainted without being flattened.
This commit is contained in:
parent
2a09a04c2a
commit
701440efd8
@ -2656,6 +2656,101 @@ _clutter_actor_get_pick_id (ClutterActor *self)
|
||||
return self->priv->pick_id;
|
||||
}
|
||||
|
||||
/* This is the same as clutter_actor_add_effect except that it doesn't
|
||||
queue a redraw and it doesn't notify on the effect property */
|
||||
static void
|
||||
_clutter_actor_add_effect_internal (ClutterActor *self,
|
||||
ClutterEffect *effect)
|
||||
{
|
||||
ClutterActorPrivate *priv = self->priv;
|
||||
|
||||
if (priv->effects == NULL)
|
||||
{
|
||||
priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
|
||||
priv->effects->actor = self;
|
||||
}
|
||||
|
||||
_clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
|
||||
}
|
||||
|
||||
/* This is the same as clutter_actor_remove_effect except that it doesn't
|
||||
queue a redraw and it doesn't notify on the effect property */
|
||||
static void
|
||||
_clutter_actor_remove_effect_internal (ClutterActor *self,
|
||||
ClutterEffect *effect)
|
||||
{
|
||||
ClutterActorPrivate *priv = self->priv;
|
||||
|
||||
if (priv->effects == NULL)
|
||||
return;
|
||||
|
||||
_clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
needs_flatten_effect (ClutterActor *self)
|
||||
{
|
||||
ClutterActorPrivate *priv = self->priv;
|
||||
|
||||
switch (priv->offscreen_redirect)
|
||||
{
|
||||
case CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY:
|
||||
if (!clutter_actor_has_overlaps (self))
|
||||
return FALSE;
|
||||
/* flow through */
|
||||
case CLUTTER_OFFSCREEN_REDIRECT_ALWAYS_FOR_OPACITY:
|
||||
return clutter_actor_get_paint_opacity (self) < 255;
|
||||
|
||||
case CLUTTER_OFFSCREEN_REDIRECT_ALWAYS:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static void
|
||||
add_or_remove_flatten_effect (ClutterActor *self)
|
||||
{
|
||||
ClutterActorPrivate *priv = self->priv;
|
||||
|
||||
/* Add or remove the flatten effect depending on the
|
||||
offscreen-redirect property. */
|
||||
if (needs_flatten_effect (self))
|
||||
{
|
||||
if (priv->flatten_effect == NULL)
|
||||
{
|
||||
ClutterActorMeta *actor_meta;
|
||||
gint priority;
|
||||
|
||||
priv->flatten_effect = _clutter_flatten_effect_new ();
|
||||
/* Keep a reference to the effect so that we can queue
|
||||
redraws from it */
|
||||
g_object_ref_sink (priv->flatten_effect);
|
||||
|
||||
/* Set the priority of the effect to high so that it will
|
||||
always be applied to the actor first. It uses an internal
|
||||
priority so that it won't be visible to applications */
|
||||
actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
|
||||
priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
|
||||
_clutter_actor_meta_set_priority (actor_meta, priority);
|
||||
|
||||
/* This will add the effect without queueing a redraw */
|
||||
_clutter_actor_add_effect_internal (self, priv->flatten_effect);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (priv->flatten_effect != NULL)
|
||||
{
|
||||
/* Destroy the effect so that it will lose its fbo cache of
|
||||
the actor */
|
||||
_clutter_actor_remove_effect_internal (self, priv->flatten_effect);
|
||||
g_object_unref (priv->flatten_effect);
|
||||
priv->flatten_effect = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_paint:
|
||||
* @self: A #ClutterActor
|
||||
@ -2757,6 +2852,12 @@ clutter_actor_paint (ClutterActor *self)
|
||||
{
|
||||
CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
|
||||
|
||||
/* We check whether we need to add the flatten effect before
|
||||
each paint so that we can avoid having a mechanism for
|
||||
applications to notify when the value of the
|
||||
has_overlaps virtual changes. */
|
||||
add_or_remove_flatten_effect (self);
|
||||
|
||||
/* We save the current paint volume so that the next time the
|
||||
* actor queues a redraw we can constrain the redraw to just
|
||||
* cover the union of the new bounding box and the old.
|
||||
@ -3648,6 +3749,17 @@ clutter_actor_real_get_paint_volume (ClutterActor *self,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_actor_real_has_overlaps (ClutterActor *self)
|
||||
{
|
||||
/* By default we'll assume that all actors need an offscreen
|
||||
redirect to get the correct opacity. This effectively favours
|
||||
accuracy over efficiency. Actors such as ClutterTexture that
|
||||
would never need an offscreen redirect can override this to
|
||||
return FALSE. */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_actor_class_init (ClutterActorClass *klass)
|
||||
{
|
||||
@ -4052,7 +4164,7 @@ clutter_actor_class_init (ClutterActorClass *klass)
|
||||
P_("Whether to flatten the actor into a "
|
||||
"single image"),
|
||||
CLUTTER_TYPE_OFFSCREEN_REDIRECT,
|
||||
CLUTTER_OFFSCREEN_REDIRECT_NEVER,
|
||||
CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY,
|
||||
CLUTTER_PARAM_READWRITE);
|
||||
obj_props[PROP_OFFSCREEN_REDIRECT] = pspec;
|
||||
g_object_class_install_property (object_class,
|
||||
@ -5092,6 +5204,7 @@ clutter_actor_class_init (ClutterActorClass *klass)
|
||||
klass->apply_transform = clutter_actor_real_apply_transform;
|
||||
klass->get_accessible = clutter_actor_real_get_accessible;
|
||||
klass->get_paint_volume = clutter_actor_real_get_paint_volume;
|
||||
klass->has_overlaps = clutter_actor_real_has_overlaps;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -5104,7 +5217,7 @@ clutter_actor_init (ClutterActor *self)
|
||||
priv->parent_actor = NULL;
|
||||
priv->has_clip = FALSE;
|
||||
priv->opacity = 0xff;
|
||||
priv->offscreen_redirect = CLUTTER_OFFSCREEN_REDIRECT_NEVER;
|
||||
priv->offscreen_redirect = CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY;
|
||||
priv->id = _clutter_context_acquire_id (self);
|
||||
priv->pick_id = -1;
|
||||
priv->scale_x = 1.0;
|
||||
@ -7420,7 +7533,7 @@ clutter_actor_get_opacity (ClutterActor *self)
|
||||
* some cases be a performance lose so it is important to determine
|
||||
* which value is right for an actor before modifying this value. For
|
||||
* example, there is never any reason to flatten an actor that is just
|
||||
* a single texture (such as a ClutterTexture) because it is
|
||||
* a single texture (such as a #ClutterTexture) because it is
|
||||
* effectively already cached in an image so the offscreen would be
|
||||
* redundant. Also if the actor contains primitives that are far apart
|
||||
* with a large transparent area in the middle (such as a large
|
||||
@ -7433,28 +7546,35 @@ clutter_actor_get_opacity (ClutterActor *self)
|
||||
* forwards on the opacity to all of the children. If the children are
|
||||
* overlapping then it will appear as if they are two separate glassy
|
||||
* objects and there will be a break in the color where they
|
||||
* overlap. By setting the offscreen-redirect to
|
||||
* %CLUTTER_OFFSCREEN_REDIRECT_OPACITY_ONLY it will be as if the two
|
||||
* opaque objects are combined into one and then made transparent
|
||||
* overlap. By redirecting to an offscreen buffer it will be as if the
|
||||
* two opaque objects are combined into one and then made transparent
|
||||
* which is usually what is expected.
|
||||
*
|
||||
* The image below demonstrates the difference between the fast
|
||||
* default opacity and the correct but inefficient opacity achieved
|
||||
* through the offscreen redirect. The image shows two Clutter groups,
|
||||
* each containing a red and a green rectangle which overlap. The
|
||||
* opacity on the group is set to 128 (which is 50%). When the
|
||||
* offscreen redirect is not used, the red rectangle can be seen
|
||||
* through the blue rectangle as if the two rectangles were separately
|
||||
* transparent. When the redirect is used the group as a whole is
|
||||
* transparent instead so the red rectangle is not visible where they
|
||||
* overlap.
|
||||
* The image below demonstrates the difference between redirecting and
|
||||
* not. The image shows two Clutter groups, each containing a red and
|
||||
* a green rectangle which overlap. The opacity on the group is set to
|
||||
* 128 (which is 50%). When the offscreen redirect is not used, the
|
||||
* red rectangle can be seen through the blue rectangle as if the two
|
||||
* rectangles were separately transparent. When the redirect is used
|
||||
* the group as a whole is transparent instead so the red rectangle is
|
||||
* not visible where they overlap.
|
||||
*
|
||||
* <figure id="offscreen-redirect">
|
||||
* <title>Sample of using an offscreen redirect for transparency</title>
|
||||
* <graphic fileref="offscreen-redirect.png" format="PNG"/>
|
||||
* </figure>
|
||||
*
|
||||
* The default value is %CLUTTER_OFFSCREEN_REDIRECT_NEVER.
|
||||
* The default behaviour is
|
||||
* %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY. This will end up
|
||||
* redirecting actors whenever they are semi-transparent unless their
|
||||
* has_overlaps() virtual returns %FALSE. This should mean that
|
||||
* generally all actors will be rendered with the correct opacity and
|
||||
* certain actors that don't need the offscreen redirect (such as
|
||||
* #ClutterTexture) will paint directly for efficiency.
|
||||
*
|
||||
* Custom actors that don't contain any overlapping primitives are
|
||||
* recommended to override the has_overlaps() virtual to return %FALSE
|
||||
* for maximum efficiency.
|
||||
*
|
||||
* Since: 1.8
|
||||
*/
|
||||
@ -7472,37 +7592,15 @@ clutter_actor_set_offscreen_redirect (ClutterActor *self,
|
||||
{
|
||||
priv->offscreen_redirect = redirect;
|
||||
|
||||
if (priv->flatten_effect == NULL)
|
||||
{
|
||||
ClutterActorMeta *actor_meta;
|
||||
gint priority;
|
||||
|
||||
priv->flatten_effect = _clutter_flatten_effect_new ();
|
||||
/* Keep a reference to the effect so that we can queue
|
||||
redraws from it */
|
||||
g_object_ref_sink (priv->flatten_effect);
|
||||
|
||||
/* Set the priority of the effect to high so that it will
|
||||
always be applied to the actor first. It uses an internal
|
||||
priority so that it won't be visible to applications */
|
||||
actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
|
||||
priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
|
||||
_clutter_actor_meta_set_priority (actor_meta, priority);
|
||||
|
||||
/* This will also queue a full redraw of the actor */
|
||||
clutter_actor_add_effect (self, priv->flatten_effect);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Queue a redraw from the effect so that it can use its
|
||||
cached image if available instead of having to redraw the
|
||||
actual actor. If it doesn't end up using the FBO then the
|
||||
effect is still able to continue the paint anyway */
|
||||
_clutter_actor_queue_redraw_full (self,
|
||||
0, /* flags */
|
||||
NULL, /* clip */
|
||||
priv->flatten_effect);
|
||||
}
|
||||
/* Queue a redraw from the effect so that it can use its cached
|
||||
image if available instead of having to redraw the actual
|
||||
actor. If it doesn't end up using the FBO then the effect is
|
||||
still able to continue the paint anyway. If there is no
|
||||
effect then this is equivalent to queuing a full redraw */
|
||||
_clutter_actor_queue_redraw_full (self,
|
||||
0, /* flags */
|
||||
NULL, /* clip */
|
||||
priv->flatten_effect);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self),
|
||||
obj_props[PROP_OFFSCREEN_REDIRECT]);
|
||||
@ -11744,20 +11842,10 @@ void
|
||||
clutter_actor_add_effect (ClutterActor *self,
|
||||
ClutterEffect *effect)
|
||||
{
|
||||
ClutterActorPrivate *priv;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
||||
g_return_if_fail (CLUTTER_IS_EFFECT (effect));
|
||||
|
||||
priv = self->priv;
|
||||
|
||||
if (priv->effects == NULL)
|
||||
{
|
||||
priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
|
||||
priv->effects->actor = self;
|
||||
}
|
||||
|
||||
_clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
|
||||
_clutter_actor_add_effect_internal (self, effect);
|
||||
|
||||
clutter_actor_queue_redraw (self);
|
||||
|
||||
@ -11810,17 +11898,10 @@ void
|
||||
clutter_actor_remove_effect (ClutterActor *self,
|
||||
ClutterEffect *effect)
|
||||
{
|
||||
ClutterActorPrivate *priv;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
||||
g_return_if_fail (CLUTTER_IS_EFFECT (effect));
|
||||
|
||||
priv = self->priv;
|
||||
|
||||
if (priv->effects == NULL)
|
||||
return;
|
||||
|
||||
_clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
|
||||
_clutter_actor_remove_effect_internal (self, effect);
|
||||
|
||||
clutter_actor_queue_redraw (self);
|
||||
|
||||
@ -12236,6 +12317,27 @@ clutter_actor_get_paint_box (ClutterActor *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_has_overlaps:
|
||||
* @self: A #ClutterActor
|
||||
*
|
||||
* Return value: whether the actor may contain overlapping
|
||||
* primitives. Clutter uses this to determine whether the painting
|
||||
* should be redirected to an offscreen buffer to correctly implement
|
||||
* the opacity property. Custom actors can override this by
|
||||
* implementing the has_overlaps virtual. See
|
||||
* clutter_actor_set_offscreen_redirect() for more information.
|
||||
*
|
||||
* Since: 1.8
|
||||
*/
|
||||
gboolean
|
||||
clutter_actor_has_overlaps (ClutterActor *self)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
|
||||
|
||||
return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
|
||||
}
|
||||
|
||||
gint
|
||||
_clutter_actor_get_n_children (ClutterActor *self)
|
||||
{
|
||||
|
@ -118,12 +118,14 @@ typedef enum
|
||||
|
||||
/**
|
||||
* ClutterOffscreenRedirect:
|
||||
* @CLUTTER_OFFSCREEN_REDIRECT_NEVER: Never redirect the actor to an
|
||||
* offscreen buffer.
|
||||
* @CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY: Only redirect
|
||||
* the actor if it is semi-transparent and its has_overlaps()
|
||||
* virtual returns %TRUE. This is the default.
|
||||
* @CLUTTER_OFFSCREEN_REDIRECT_ALWAYS_FOR_OPACITY: Always redirect the
|
||||
* actor if it is semi-transparent regardless of the return value of
|
||||
* its has_overlaps() virtual.
|
||||
* @CLUTTER_OFFSCREEN_REDIRECT_ALWAYS: Always redirect the actor to an
|
||||
* offscreen buffer.
|
||||
* @CLUTTER_OFFSCREEN_REDIRECT_OPACITY_ONLY: Only redirect the actor if
|
||||
* it is semi-transparent.
|
||||
* offscreen buffer even if it is fully opaque.
|
||||
*
|
||||
* Possible values to pass to clutter_actor_set_offscreen_redirect().
|
||||
*
|
||||
@ -131,9 +133,9 @@ typedef enum
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
CLUTTER_OFFSCREEN_REDIRECT_NEVER,
|
||||
CLUTTER_OFFSCREEN_REDIRECT_ALWAYS,
|
||||
CLUTTER_OFFSCREEN_REDIRECT_OPACITY_ONLY
|
||||
CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY,
|
||||
CLUTTER_OFFSCREEN_REDIRECT_ALWAYS_FOR_OPACITY,
|
||||
CLUTTER_OFFSCREEN_REDIRECT_ALWAYS
|
||||
} ClutterOffscreenRedirect;
|
||||
|
||||
/**
|
||||
@ -235,6 +237,10 @@ struct _ClutterActor
|
||||
* describes the actor to an assistive technology.
|
||||
* @get_paint_volume: virtual function, for sub-classes to define their
|
||||
* #ClutterPaintVolume
|
||||
* @has_overlaps: virtual function for
|
||||
* sub-classes to advertise whether they need an offscreen redirect
|
||||
* to get the correct opacity. See
|
||||
* clutter_actor_set_offscreen_redirect() for details.
|
||||
*
|
||||
* Base class for actors.
|
||||
*/
|
||||
@ -312,9 +318,11 @@ struct _ClutterActorClass
|
||||
gboolean (* get_paint_volume) (ClutterActor *actor,
|
||||
ClutterPaintVolume *volume);
|
||||
|
||||
gboolean (* has_overlaps) (ClutterActor *self);
|
||||
|
||||
/*< private >*/
|
||||
/* padding for future expansion */
|
||||
gpointer _padding_dummy[29];
|
||||
gpointer _padding_dummy[28];
|
||||
};
|
||||
|
||||
GType clutter_actor_get_type (void) G_GNUC_CONST;
|
||||
@ -610,6 +618,8 @@ const ClutterPaintVolume *clutter_actor_get_transformed_paint_volume (ClutterAc
|
||||
gboolean clutter_actor_get_paint_box (ClutterActor *self,
|
||||
ClutterActorBox *box);
|
||||
|
||||
gboolean clutter_actor_has_overlaps (ClutterActor *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_ACTOR_H__ */
|
||||
|
@ -221,6 +221,19 @@ clutter_clone_get_paint_volume (ClutterActor *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_clone_has_overlaps (ClutterActor *self)
|
||||
{
|
||||
ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv;
|
||||
|
||||
/* The clone has overlaps iff the source has overlaps */
|
||||
|
||||
if (priv->clone_source == NULL)
|
||||
return FALSE;
|
||||
|
||||
return clutter_actor_has_overlaps (priv->clone_source);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_clone_allocate (ClutterActor *self,
|
||||
const ClutterActorBox *box,
|
||||
@ -309,6 +322,7 @@ clutter_clone_class_init (ClutterCloneClass *klass)
|
||||
actor_class->get_preferred_width = clutter_clone_get_preferred_width;
|
||||
actor_class->get_preferred_height = clutter_clone_get_preferred_height;
|
||||
actor_class->allocate = clutter_clone_allocate;
|
||||
actor_class->has_overlaps = clutter_clone_has_overlaps;
|
||||
|
||||
gobject_class->dispose = clutter_clone_dispose;
|
||||
gobject_class->set_property = clutter_clone_set_property;
|
||||
|
@ -23,7 +23,9 @@
|
||||
*/
|
||||
|
||||
/* This is an internal-only effect used to implement the
|
||||
'flatness' property of ClutterActor */
|
||||
'offscreen-redirect' property of ClutterActor. It doesn't actually
|
||||
need to do anything on top of the ClutterOffscreenEffect class so
|
||||
it only exists because that class is abstract */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
@ -33,50 +35,18 @@
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-actor-private.h"
|
||||
|
||||
static void
|
||||
_clutter_flatten_effect_set_actor (ClutterActorMeta *meta,
|
||||
ClutterActor *actor);
|
||||
|
||||
static void
|
||||
_clutter_flatten_effect_run (ClutterEffect *effect,
|
||||
ClutterEffectRunFlags flags);
|
||||
|
||||
G_DEFINE_TYPE (ClutterFlattenEffect,
|
||||
_clutter_flatten_effect,
|
||||
CLUTTER_TYPE_OFFSCREEN_EFFECT);
|
||||
|
||||
#define CLUTTER_FLATTEN_EFFECT_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_FLATTEN_EFFECT, \
|
||||
ClutterFlattenEffectPrivate))
|
||||
|
||||
struct _ClutterFlattenEffectPrivate
|
||||
{
|
||||
ClutterActor *actor;
|
||||
|
||||
/* This records whether the last paint went through the FBO or if it
|
||||
was painted directly. We need to know this so we can force the
|
||||
offscreen effect to clear its image when we switch from rendering
|
||||
directly to rendering through the FBO */
|
||||
gboolean last_paint_used_fbo;
|
||||
};
|
||||
|
||||
static void
|
||||
_clutter_flatten_effect_class_init (ClutterFlattenEffectClass *klass)
|
||||
{
|
||||
ClutterActorMetaClass *actor_meta_class = (ClutterActorMetaClass *) klass;
|
||||
ClutterEffectClass *effect_class = (ClutterEffectClass *) klass;
|
||||
|
||||
actor_meta_class->set_actor = _clutter_flatten_effect_set_actor;
|
||||
|
||||
effect_class->run = _clutter_flatten_effect_run;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (ClutterFlattenEffectPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
_clutter_flatten_effect_init (ClutterFlattenEffect *self)
|
||||
{
|
||||
self->priv = CLUTTER_FLATTEN_EFFECT_GET_PRIVATE (self);
|
||||
}
|
||||
|
||||
ClutterEffect *
|
||||
@ -84,68 +54,3 @@ _clutter_flatten_effect_new (void)
|
||||
{
|
||||
return g_object_new (CLUTTER_TYPE_FLATTEN_EFFECT, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_clutter_flatten_effect_is_using_fbo (ClutterFlattenEffect *opacity_effect)
|
||||
{
|
||||
ClutterFlattenEffectPrivate *priv = opacity_effect->priv;
|
||||
|
||||
switch (clutter_actor_get_offscreen_redirect (priv->actor))
|
||||
{
|
||||
case CLUTTER_OFFSCREEN_REDIRECT_NEVER:
|
||||
return FALSE;
|
||||
|
||||
case CLUTTER_OFFSCREEN_REDIRECT_ALWAYS:
|
||||
return TRUE;
|
||||
|
||||
case CLUTTER_OFFSCREEN_REDIRECT_OPACITY_ONLY:
|
||||
return clutter_actor_get_paint_opacity (priv->actor) < 255;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_clutter_flatten_effect_set_actor (ClutterActorMeta *meta,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
ClutterFlattenEffect *opacity_effect = CLUTTER_FLATTEN_EFFECT (meta);
|
||||
ClutterFlattenEffectPrivate *priv = opacity_effect->priv;
|
||||
|
||||
CLUTTER_ACTOR_META_CLASS (_clutter_flatten_effect_parent_class)->
|
||||
set_actor (meta, actor);
|
||||
|
||||
/* we keep a back pointer here, to avoid going through the ActorMeta */
|
||||
priv->actor = clutter_actor_meta_get_actor (meta);
|
||||
}
|
||||
|
||||
static void
|
||||
_clutter_flatten_effect_run (ClutterEffect *effect,
|
||||
ClutterEffectRunFlags flags)
|
||||
{
|
||||
ClutterFlattenEffect *opacity_effect = CLUTTER_FLATTEN_EFFECT (effect);
|
||||
ClutterFlattenEffectPrivate *priv = opacity_effect->priv;
|
||||
|
||||
if (_clutter_flatten_effect_is_using_fbo (opacity_effect))
|
||||
{
|
||||
/* If the last paint bypassed the FBO then we'll pretend the
|
||||
actor is dirty so that the offscreen will clear its image */
|
||||
if (!priv->last_paint_used_fbo)
|
||||
{
|
||||
flags |= CLUTTER_EFFECT_RUN_ACTOR_DIRTY;
|
||||
priv->last_paint_used_fbo = TRUE;
|
||||
}
|
||||
|
||||
/* Let the offscreen effect paint the actor through the FBO */
|
||||
CLUTTER_EFFECT_CLASS (_clutter_flatten_effect_parent_class)->
|
||||
run (effect, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just let the actor paint directly to the stage */
|
||||
clutter_actor_continue_paint (priv->actor);
|
||||
|
||||
priv->last_paint_used_fbo = FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -62,8 +62,6 @@ struct _ClutterFlattenEffectClass
|
||||
struct _ClutterFlattenEffect
|
||||
{
|
||||
ClutterOffscreenEffect parent;
|
||||
|
||||
ClutterFlattenEffectPrivate *priv;
|
||||
};
|
||||
|
||||
GType _clutter_flatten_effect_get_type (void) G_GNUC_CONST;
|
||||
|
@ -162,6 +162,14 @@ clutter_rectangle_get_paint_volume (ClutterActor *self,
|
||||
volume);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_rectangle_has_overlaps (ClutterActor *self)
|
||||
{
|
||||
/* Rectangles never need an offscreen redirect because there are
|
||||
never any overlapping primitives */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_rectangle_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
@ -243,6 +251,7 @@ clutter_rectangle_class_init (ClutterRectangleClass *klass)
|
||||
|
||||
actor_class->paint = clutter_rectangle_paint;
|
||||
actor_class->get_paint_volume = clutter_rectangle_get_paint_volume;
|
||||
actor_class->has_overlaps = clutter_rectangle_has_overlaps;
|
||||
|
||||
gobject_class->finalize = clutter_rectangle_finalize;
|
||||
gobject_class->dispose = clutter_rectangle_dispose;
|
||||
|
@ -409,6 +409,14 @@ clutter_texture_allocate (ClutterActor *self,
|
||||
clutter_actor_allocate_preferred_size (priv->fbo_source, flags);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_texture_has_overlaps (ClutterActor *self)
|
||||
{
|
||||
/* Textures never need an offscreen redirect because there are never
|
||||
any overlapping primitives */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_viewport_with_buffer_under_fbo_source (ClutterActor *fbo_source,
|
||||
int viewport_width,
|
||||
@ -980,6 +988,7 @@ clutter_texture_class_init (ClutterTextureClass *klass)
|
||||
actor_class->get_paint_volume = clutter_texture_get_paint_volume;
|
||||
actor_class->realize = clutter_texture_realize;
|
||||
actor_class->unrealize = clutter_texture_unrealize;
|
||||
actor_class->has_overlaps = clutter_texture_has_overlaps;
|
||||
|
||||
actor_class->get_preferred_width = clutter_texture_get_preferred_width;
|
||||
actor_class->get_preferred_height = clutter_texture_get_preferred_height;
|
||||
|
@ -299,6 +299,7 @@ clutter_actor_event
|
||||
clutter_actor_should_pick_paint
|
||||
clutter_actor_map
|
||||
clutter_actor_unmap
|
||||
clutter_actor_has_overlaps
|
||||
|
||||
<SUBSECTION>
|
||||
ClutterAllocationFlags
|
||||
|
@ -33,7 +33,7 @@ GType foo_actor_get_type (void) G_GNUC_CONST;
|
||||
G_DEFINE_TYPE (FooActor, foo_actor, CLUTTER_TYPE_ACTOR);
|
||||
|
||||
static void
|
||||
foo_actor_class_paint (ClutterActor *actor)
|
||||
foo_actor_paint (ClutterActor *actor)
|
||||
{
|
||||
FooActor *foo_actor = (FooActor *) actor;
|
||||
ClutterActorBox allocation;
|
||||
@ -55,19 +55,26 @@ foo_actor_class_paint (ClutterActor *actor)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
foo_actor_class_get_paint_volume (ClutterActor *actor,
|
||||
ClutterPaintVolume *volume)
|
||||
foo_actor_get_paint_volume (ClutterActor *actor,
|
||||
ClutterPaintVolume *volume)
|
||||
{
|
||||
return clutter_paint_volume_set_from_allocation (volume, actor);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
foo_actor_has_overlaps (ClutterActor *actor)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
foo_actor_class_init (FooActorClass *klass)
|
||||
{
|
||||
ClutterActorClass *actor_class = (ClutterActorClass *) klass;
|
||||
|
||||
actor_class->paint = foo_actor_class_paint;
|
||||
actor_class->get_paint_volume = foo_actor_class_get_paint_volume;
|
||||
actor_class->paint = foo_actor_paint;
|
||||
actor_class->get_paint_volume = foo_actor_get_paint_volume;
|
||||
actor_class->has_overlaps = foo_actor_has_overlaps;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -75,6 +82,40 @@ foo_actor_init (FooActor *self)
|
||||
{
|
||||
}
|
||||
|
||||
typedef struct _FooGroup FooGroup;
|
||||
typedef struct _FooGroupClass FooGroupClass;
|
||||
|
||||
struct _FooGroupClass
|
||||
{
|
||||
ClutterGroupClass parent_class;
|
||||
};
|
||||
|
||||
struct _FooGroup
|
||||
{
|
||||
ClutterGroup parent;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (FooGroup, foo_group, CLUTTER_TYPE_GROUP);
|
||||
|
||||
static gboolean
|
||||
foo_group_has_overlaps (ClutterActor *actor)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
foo_group_class_init (FooGroupClass *klass)
|
||||
{
|
||||
ClutterActorClass *actor_class = (ClutterActorClass *) klass;
|
||||
|
||||
actor_class->has_overlaps = foo_group_has_overlaps;
|
||||
}
|
||||
|
||||
static void
|
||||
foo_group_init (FooGroup *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
verify_results (Data *data,
|
||||
guint8 expected_color_red,
|
||||
@ -155,7 +196,7 @@ timeout_cb (gpointer user_data)
|
||||
it needs to fill the cache first. It should be painted with full
|
||||
opacity */
|
||||
clutter_actor_set_offscreen_redirect
|
||||
(data->container, CLUTTER_OFFSCREEN_REDIRECT_OPACITY_ONLY);
|
||||
(data->container, CLUTTER_OFFSCREEN_REDIRECT_ALWAYS_FOR_OPACITY);
|
||||
verify_results (data,
|
||||
255, 127, 127,
|
||||
1,
|
||||
@ -242,7 +283,7 @@ test_offscreen_redirect (TestConformSimpleFixture *fixture,
|
||||
|
||||
data.parent_container = clutter_group_new ();
|
||||
|
||||
data.container = clutter_group_new ();
|
||||
data.container = g_object_new (foo_group_get_type (), NULL);
|
||||
|
||||
data.foo_actor = g_object_new (foo_actor_get_type (), NULL);
|
||||
clutter_actor_set_size (CLUTTER_ACTOR (data.foo_actor), 100, 100);
|
||||
|
Loading…
Reference in New Issue
Block a user