paint volumes: another pass at the design
This is a fairly extensive second pass at exposing paint volumes for actors. The API has changed to allow clutter_actor_get_paint_volume to fail since there are times - such as when an actor isn't a descendent of the stage - when the volume can't be determined. Another example is when something has connected to the "paint" signal of the actor and we simply have no way of knowing what might be drawn in that handler. The API has also be changed to return a const ClutterPaintVolume pointer (transfer none) so we can avoid having to dynamically allocate the volumes in the most common/performance critical code paths. Profiling was showing the slice allocation of volumes taking about 1% of an apps time, for some fairly basic tests. Most volumes can now simply be allocated on the stack; for clutter_actor_get_paint_volume we return a pointer to &priv->paint_volume and if we need a more dynamic allocation there is now a _clutter_stage_paint_volume_stack_allocate() mechanism which lets us allocate data which expires at the start of the next frame. The API has been extended to make it easier to implement get_paint_volume for containers by using clutter_actor_get_transformed_paint_volume and clutter_paint_volume_union. The first allows you to query the paint volume of a child but transformed into parent actor coordinates. The second lets you combine volumes together so you can union all the volumes for a container's children and report that as the container's own volume. The representation of paint volumes has been updated to consider that 2D actors are the most common. The effect apis, clutter-texture and clutter-group have been update accordingly.
This commit is contained in:
parent
48a24a2e08
commit
3540d222e1
File diff suppressed because it is too large
Load Diff
@ -306,7 +306,7 @@ struct _ClutterActorClass
|
||||
/* accessibility support */
|
||||
AtkObject * (* get_accessible) (ClutterActor *actor);
|
||||
|
||||
void (* get_paint_volume) (ClutterActor *actor,
|
||||
gboolean (* get_paint_volume) (ClutterActor *actor,
|
||||
ClutterPaintVolume *volume);
|
||||
|
||||
/*< private >*/
|
||||
@ -589,8 +589,12 @@ gboolean clutter_actor_has_allocation (ClutterActor *sel
|
||||
AtkObject * clutter_actor_get_accessible (ClutterActor *self);
|
||||
|
||||
gboolean clutter_actor_has_key_focus (ClutterActor *self);
|
||||
ClutterPaintVolume *clutter_actor_get_paint_volume (ClutterActor *self);
|
||||
void clutter_actor_get_paint_box (ClutterActor *self,
|
||||
|
||||
const ClutterPaintVolume *clutter_actor_get_paint_volume (ClutterActor *self);
|
||||
const ClutterPaintVolume *clutter_actor_get_transformed_paint_volume (ClutterActor *self,
|
||||
ClutterActor *relative_to_ancestor);
|
||||
|
||||
gboolean clutter_actor_get_paint_box (ClutterActor *self,
|
||||
ClutterActorBox *box);
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -255,7 +255,7 @@ out:
|
||||
parent->paint_target (effect);
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
clutter_blur_effect_get_paint_volume (ClutterEffect *effect,
|
||||
ClutterPaintVolume *volume)
|
||||
{
|
||||
@ -273,6 +273,8 @@ clutter_blur_effect_get_paint_volume (ClutterEffect *effect,
|
||||
clutter_paint_volume_set_origin (volume, &origin);
|
||||
clutter_paint_volume_set_width (volume, cur_width);
|
||||
clutter_paint_volume_set_height (volume, cur_height);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -191,10 +191,11 @@ clutter_effect_real_post_paint (ClutterEffect *effect)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
clutter_effect_real_get_paint_volume (ClutterEffect *effect,
|
||||
ClutterPaintVolume *volume)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -226,12 +227,12 @@ _clutter_effect_post_paint (ClutterEffect *effect)
|
||||
CLUTTER_EFFECT_GET_CLASS (effect)->post_paint (effect);
|
||||
}
|
||||
|
||||
void
|
||||
gboolean
|
||||
_clutter_effect_get_paint_volume (ClutterEffect *effect,
|
||||
ClutterPaintVolume *volume)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_EFFECT (effect));
|
||||
g_return_if_fail (volume != NULL);
|
||||
g_return_val_if_fail (CLUTTER_IS_EFFECT (effect), FALSE);
|
||||
g_return_val_if_fail (volume != NULL, FALSE);
|
||||
|
||||
CLUTTER_EFFECT_GET_CLASS (effect)->get_paint_volume (effect, volume);
|
||||
return CLUTTER_EFFECT_GET_CLASS (effect)->get_paint_volume (effect, volume);
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ struct _ClutterEffectClass
|
||||
gboolean (* pre_paint) (ClutterEffect *effect);
|
||||
void (* post_paint) (ClutterEffect *effect);
|
||||
|
||||
void (* get_paint_volume) (ClutterEffect *effect,
|
||||
gboolean (* get_paint_volume) (ClutterEffect *effect,
|
||||
ClutterPaintVolume *volume);
|
||||
|
||||
/*< private >*/
|
||||
|
@ -386,8 +386,32 @@ clutter_group_real_hide_all (ClutterActor *actor)
|
||||
NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_group_real_get_paint_volume (ClutterActor *actor,
|
||||
ClutterPaintVolume *volume)
|
||||
{
|
||||
ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv;
|
||||
GList *l;
|
||||
|
||||
if (priv->children == NULL)
|
||||
return TRUE;
|
||||
|
||||
for (l = priv->children; l != NULL; l = l->next)
|
||||
{
|
||||
ClutterActor *child = l->data;
|
||||
const ClutterPaintVolume *child_volume;
|
||||
|
||||
/* This gets the paint volume of the child transformed into the
|
||||
* group's coordinate space... */
|
||||
child_volume = clutter_actor_get_transformed_paint_volume (child, actor);
|
||||
if (!child_volume)
|
||||
return FALSE;
|
||||
|
||||
clutter_paint_volume_union (volume, child_volume);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_group_class_init (ClutterGroupClass *klass)
|
||||
@ -404,6 +428,7 @@ clutter_group_class_init (ClutterGroupClass *klass)
|
||||
actor_class->pick = clutter_group_real_pick;
|
||||
actor_class->show_all = clutter_group_real_show_all;
|
||||
actor_class->hide_all = clutter_group_real_hide_all;
|
||||
actor_class->get_paint_volume = clutter_group_real_get_paint_volume;
|
||||
|
||||
gobject_class->dispose = clutter_group_dispose;
|
||||
|
||||
|
@ -665,7 +665,7 @@ _clutter_do_pick (ClutterStage *stage,
|
||||
*/
|
||||
CLUTTER_TIMER_START (_clutter_uprof_context, pick_paint);
|
||||
context->pick_mode = mode;
|
||||
clutter_actor_paint (CLUTTER_ACTOR (stage));
|
||||
_clutter_stage_do_paint (stage);
|
||||
context->pick_mode = CLUTTER_PICK_NONE;
|
||||
CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_paint);
|
||||
|
||||
|
@ -130,11 +130,10 @@ clutter_offscreen_effect_real_create_texture (ClutterOffscreenEffect *effect,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_fbo (ClutterEffect *effect)
|
||||
update_fbo (ClutterEffect *effect, int fbo_width, int fbo_height)
|
||||
{
|
||||
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
|
||||
ClutterOffscreenEffectPrivate *priv = self->priv;
|
||||
gfloat width, height;
|
||||
CoglHandle texture;
|
||||
|
||||
priv->stage = clutter_actor_get_stage (priv->actor);
|
||||
@ -147,21 +146,8 @@ update_fbo (ClutterEffect *effect)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* the target should at least be big enough to contain the
|
||||
* transformed allocation of the actor
|
||||
*
|
||||
* FIXME - this is actually not enough: we need the paint area
|
||||
* to make this work reliably
|
||||
*/
|
||||
{
|
||||
ClutterActorBox box = { 0, };
|
||||
|
||||
clutter_actor_get_paint_box (priv->actor, &box);
|
||||
clutter_actor_box_get_size (&box, &width, &height);
|
||||
}
|
||||
|
||||
if (priv->target_width == width &&
|
||||
priv->target_height == height)
|
||||
if (priv->target_width == fbo_width &&
|
||||
priv->target_height == fbo_height)
|
||||
return TRUE;
|
||||
|
||||
if (priv->target != COGL_INVALID_HANDLE)
|
||||
@ -172,7 +158,8 @@ update_fbo (ClutterEffect *effect)
|
||||
|
||||
priv->target = cogl_material_new ();
|
||||
|
||||
texture = clutter_offscreen_effect_create_texture (self, width, height);
|
||||
texture =
|
||||
clutter_offscreen_effect_create_texture (self, fbo_width, fbo_height);
|
||||
if (texture == COGL_INVALID_HANDLE)
|
||||
return FALSE;
|
||||
|
||||
@ -203,49 +190,16 @@ update_fbo (ClutterEffect *effect)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
get_screen_offsets (ClutterActor *actor,
|
||||
gfloat *x_offset,
|
||||
gfloat *y_offset)
|
||||
{
|
||||
gfloat v[4] = { 0, };
|
||||
|
||||
if (CLUTTER_ACTOR_IS_TOPLEVEL (actor))
|
||||
{
|
||||
/* trivial optimization: a top-level actor is always going to
|
||||
* have a (0, 0) offset
|
||||
*/
|
||||
*x_offset = 0.0f;
|
||||
*y_offset = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClutterActorBox box = { 0, };
|
||||
|
||||
clutter_actor_get_paint_box (actor, &box);
|
||||
clutter_actor_box_get_origin (&box, x_offset, y_offset);
|
||||
}
|
||||
|
||||
/* since we're setting up a viewport with a negative offset to paint
|
||||
* in an FBO with the same modelview and projection matrices as the
|
||||
* stage, we need to offset the computed absolute allocation vertices
|
||||
* with the current viewport's X and Y offsets. this works even with
|
||||
* the default case where the viewport is set up by Clutter to be
|
||||
* (0, 0, stage_width, stage_height)
|
||||
*/
|
||||
cogl_get_viewport (v);
|
||||
*x_offset -= v[0];
|
||||
*y_offset -= v[1];
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_offscreen_effect_pre_paint (ClutterEffect *effect)
|
||||
{
|
||||
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
|
||||
ClutterOffscreenEffectPrivate *priv = self->priv;
|
||||
ClutterActorBox box;
|
||||
CoglMatrix projection;
|
||||
CoglColor transparent;
|
||||
CoglMatrix modelview;
|
||||
gfloat fbo_width, fbo_height;
|
||||
gfloat width, height;
|
||||
|
||||
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
|
||||
@ -254,7 +208,22 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect)
|
||||
if (priv->actor == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!update_fbo (effect))
|
||||
/* The paint box is the bounding box of the actor's paint volume in
|
||||
* stage coordinates. This will give us the size for the framebuffer
|
||||
* we need to redirect its rendering offscreen and its position will
|
||||
* be used to setup an offset viewport */
|
||||
if (clutter_actor_get_paint_box (priv->actor, &box))
|
||||
clutter_actor_box_get_size (&box, &fbo_width, &fbo_height);
|
||||
else
|
||||
{
|
||||
/* If we can't get a valid paint box then we fallback to
|
||||
* creating a full stage size fbo. */
|
||||
ClutterActor *stage = _clutter_actor_get_stage_internal (priv->actor);
|
||||
clutter_actor_get_size (stage, &fbo_width, &fbo_height);
|
||||
}
|
||||
|
||||
/* First assert that the framebuffer is the right size... */
|
||||
if (!update_fbo (effect, fbo_width, fbo_height))
|
||||
return FALSE;
|
||||
|
||||
/* get the current modelview matrix so that we can copy it
|
||||
@ -265,12 +234,11 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect)
|
||||
/* let's draw offscreen */
|
||||
cogl_push_framebuffer (priv->offscreen);
|
||||
|
||||
/* set up the viewport so that it has the same size of the stage,
|
||||
* and it has its origin at the same position of the stage's; also
|
||||
* set up the perspective to be the same as the stage's
|
||||
*/
|
||||
/* Set up the viewport so that it has the same size as the stage,
|
||||
* but offset it so that the actor of interest lands on our
|
||||
* framebuffer. */
|
||||
clutter_actor_get_size (priv->stage, &width, &height);
|
||||
get_screen_offsets (priv->actor, &priv->x_offset, &priv->y_offset);
|
||||
clutter_actor_box_get_origin (&box, &priv->x_offset, &priv->y_offset);
|
||||
cogl_set_viewport (-priv->x_offset, -priv->y_offset, width, height);
|
||||
|
||||
/* Copy the stage's projection matrix across to the framebuffer */
|
||||
@ -306,10 +274,10 @@ clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect)
|
||||
paint_opacity);
|
||||
cogl_set_source (priv->target);
|
||||
|
||||
/* paint the texture at the same position as the actor would be,
|
||||
* in Stage coordinates, since we set up the modelview matrix to
|
||||
* be exactly as the stage sets it up, plus the eventual offsets
|
||||
* due to offscreen effects stacking
|
||||
/* At this point we are in stage coordinates translated so if
|
||||
* we draw our texture using a textured quad the size of the paint
|
||||
* box then we will overlay where the actor would have drawn if it
|
||||
* hadn't been redirected offscreen.
|
||||
*/
|
||||
cogl_rectangle_with_texture_coords (0, 0,
|
||||
priv->target_width,
|
||||
|
@ -185,6 +185,79 @@ struct _ClutterMainContext
|
||||
ClutterSettings *settings;
|
||||
};
|
||||
|
||||
struct _ClutterPaintVolume
|
||||
{
|
||||
ClutterActor *actor;
|
||||
|
||||
/* cuboid for the volume:
|
||||
*
|
||||
* 4━━━━━━━┓5
|
||||
* ┏━━━━━━━━┓╱┃
|
||||
* ┃0 ┊7 1┃ ┃
|
||||
* ┃ ┄┄┄┄┄┃┄┃6
|
||||
* ┃3 2┃╱
|
||||
* ┗━━━━━━━━┛
|
||||
*
|
||||
* 0: top, left (origin) : always valid
|
||||
* 1: top, right : always valid
|
||||
* 2: bottom, right : updated lazily
|
||||
* 3: bottom, left : always valid
|
||||
*
|
||||
* 4: top, left, back : always valid
|
||||
* 5: top, right, back : updated lazily
|
||||
* 6: bottom, right, back : updated lazily
|
||||
* 7: bottom, left, back : updated lazily
|
||||
*
|
||||
* Elements 0, 1, 3 and 4 are filled in by the PaintVolume setters
|
||||
*
|
||||
* Note: the reason for this ordering is that we can simply ignore
|
||||
* elements 4, 5, 6 and 7 most of the time for 2D actors when
|
||||
* calculating the projected paint box.
|
||||
*/
|
||||
ClutterVertex vertices[8];
|
||||
|
||||
/* As an optimization for internally managed PaintVolumes we allow
|
||||
* initializing ClutterPaintVolume variables allocated on the stack
|
||||
* so we can avoid hammering the slice allocator. */
|
||||
guint is_static:1;
|
||||
|
||||
/* A newly initialized PaintVolume is considered empty as it is
|
||||
* degenerate on all three axis.
|
||||
*
|
||||
* We consider this carefully when we union an empty volume with
|
||||
* another so that the union simply results in a copy of the other
|
||||
* volume instead of also bounding the origin of the empty volume.
|
||||
*
|
||||
* For example this is a convenient property when calculating the
|
||||
* volume of a container as the union of the volume of its children
|
||||
* where the initial volume passed to the containers
|
||||
* ->get_paint_volume method will be empty. */
|
||||
guint is_empty:1;
|
||||
|
||||
/* TRUE when we've updated the values we calculate lazily */
|
||||
guint is_complete:1;
|
||||
|
||||
/* TRUE if vertices 4-7 can be ignored. (Only valid if complete is
|
||||
* TRUE) */
|
||||
guint is_2d:1;
|
||||
|
||||
/* Set to TRUE initialy but cleared if the paint volume is
|
||||
* transfomed by a matrix. */
|
||||
guint is_axis_aligned:1;
|
||||
|
||||
|
||||
/* Note: There is a precedence to the above bitfields that should be
|
||||
* considered whenever we implement code that manipulates
|
||||
* PaintVolumes...
|
||||
*
|
||||
* Firstly if ->is_empty == TRUE then the values for ->is_complete
|
||||
* and ->is_2d are undefined, so you should typically check
|
||||
* ->is_empty as the first priority.
|
||||
*
|
||||
* XXX: document other invariables...
|
||||
*/
|
||||
};
|
||||
|
||||
#define CLUTTER_CONTEXT() (_clutter_context_get_default ())
|
||||
ClutterMainContext *_clutter_context_get_default (void);
|
||||
gboolean _clutter_context_is_initialized (void);
|
||||
@ -239,6 +312,7 @@ void _clutter_stage_manager_set_default_stage (ClutterStageManager *stage_manage
|
||||
ClutterStage *stage);
|
||||
|
||||
/* stage */
|
||||
void _clutter_stage_do_paint (ClutterStage *stage);
|
||||
void _clutter_stage_set_window (ClutterStage *stage,
|
||||
ClutterStageWindow *stage_window);
|
||||
ClutterStageWindow *_clutter_stage_get_window (ClutterStage *stage);
|
||||
@ -283,6 +357,9 @@ void _clutter_stage_increment_picks_per_frame_counter (ClutterStage *stage);
|
||||
void _clutter_stage_reset_picks_per_frame_counter (ClutterStage *stage);
|
||||
guint _clutter_stage_get_picks_per_frame_counter (ClutterStage *stage);
|
||||
|
||||
ClutterPaintVolume *_clutter_stage_paint_volume_stack_allocate (ClutterStage *stage);
|
||||
void _clutter_stage_paint_volume_stack_free_all (ClutterStage *stage);
|
||||
|
||||
/* vfuncs implemented by backend */
|
||||
GType _clutter_backend_impl_get_type (void);
|
||||
|
||||
@ -386,7 +463,7 @@ gint32 _clutter_backend_get_units_serial (ClutterBackend *backend);
|
||||
|
||||
gboolean _clutter_effect_pre_paint (ClutterEffect *effect);
|
||||
void _clutter_effect_post_paint (ClutterEffect *effect);
|
||||
void _clutter_effect_get_paint_volume (ClutterEffect *effect,
|
||||
gboolean _clutter_effect_get_paint_volume (ClutterEffect *effect,
|
||||
ClutterPaintVolume *volume);
|
||||
|
||||
void _clutter_constraint_update_allocation (ClutterConstraint *constraint,
|
||||
@ -411,9 +488,18 @@ gpointer _clutter_event_get_platform_data (const ClutterEvent *event);
|
||||
|
||||
#endif
|
||||
|
||||
ClutterPaintVolume *_clutter_paint_volume_new (ClutterActor *actor);
|
||||
void _clutter_paint_volume_get_box (ClutterPaintVolume *pv,
|
||||
ClutterActorBox *box);
|
||||
void _clutter_paint_volume_init_static (ClutterActor *actor,
|
||||
ClutterPaintVolume *pv);
|
||||
ClutterPaintVolume *_clutter_paint_volume_new (ClutterActor *actor);
|
||||
void _clutter_paint_volume_copy_static (const ClutterPaintVolume *src_pv,
|
||||
ClutterPaintVolume *dst_pv);
|
||||
|
||||
void _clutter_paint_volume_project (ClutterPaintVolume *pv,
|
||||
const CoglMatrix *modelview,
|
||||
const CoglMatrix *projection,
|
||||
const int *viewport);
|
||||
void _clutter_paint_volume_get_bounding_box (ClutterPaintVolume *pv,
|
||||
ClutterActorBox *box);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -118,6 +118,8 @@ struct _ClutterStagePrivate
|
||||
|
||||
gint picks_per_frame;
|
||||
|
||||
GArray *paint_volume_stack;
|
||||
|
||||
guint redraw_pending : 1;
|
||||
guint is_fullscreen : 1;
|
||||
guint is_cursor_visible : 1;
|
||||
@ -309,6 +311,16 @@ clutter_stage_allocate (ClutterActor *self,
|
||||
clutter_actor_queue_redraw (self);
|
||||
}
|
||||
|
||||
/* This provides a common point of entry for painting the scenegraph
|
||||
* for picking or painting...
|
||||
*/
|
||||
void
|
||||
_clutter_stage_do_paint (ClutterStage *stage)
|
||||
{
|
||||
_clutter_stage_paint_volume_stack_free_all (stage);
|
||||
clutter_actor_paint (CLUTTER_ACTOR (stage));
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_paint (ClutterActor *self)
|
||||
{
|
||||
@ -1071,6 +1083,8 @@ clutter_stage_finalize (GObject *object)
|
||||
|
||||
g_free (stage->priv->title);
|
||||
|
||||
g_array_free (priv->paint_volume_stack, TRUE);
|
||||
|
||||
G_OBJECT_CLASS (clutter_stage_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@ -1468,6 +1482,9 @@ clutter_stage_init (ClutterStage *self)
|
||||
|
||||
_clutter_stage_set_pick_buffer_valid (self, FALSE);
|
||||
_clutter_stage_reset_picks_per_frame_counter (self);
|
||||
|
||||
priv->paint_volume_stack =
|
||||
g_array_new (FALSE, FALSE, sizeof (ClutterPaintVolume));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2986,3 +3003,33 @@ _clutter_stage_get_picks_per_frame_counter (ClutterStage *stage)
|
||||
|
||||
return stage->priv->picks_per_frame;
|
||||
}
|
||||
|
||||
ClutterPaintVolume *
|
||||
_clutter_stage_paint_volume_stack_allocate (ClutterStage *stage)
|
||||
{
|
||||
GArray *paint_volume_stack = stage->priv->paint_volume_stack;
|
||||
|
||||
g_array_set_size (paint_volume_stack,
|
||||
paint_volume_stack->len+1);
|
||||
|
||||
return &g_array_index (paint_volume_stack,
|
||||
ClutterPaintVolume,
|
||||
paint_volume_stack->len - 1);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_stage_paint_volume_stack_free_all (ClutterStage *stage)
|
||||
{
|
||||
GArray *paint_volume_stack = stage->priv->paint_volume_stack;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < paint_volume_stack->len; i++)
|
||||
{
|
||||
ClutterPaintVolume *pv =
|
||||
&g_array_index (paint_volume_stack, ClutterPaintVolume, i);
|
||||
clutter_paint_volume_free (pv);
|
||||
}
|
||||
|
||||
g_array_set_size (paint_volume_stack, 0);
|
||||
}
|
||||
|
||||
|
@ -416,8 +416,46 @@ set_viewport_with_buffer_under_fbo_source (ClutterActor *fbo_source,
|
||||
ClutterActorBox box = { 0, };
|
||||
float x_offset, y_offset;
|
||||
|
||||
clutter_actor_get_paint_box (fbo_source, &box);
|
||||
clutter_actor_box_get_origin (&box, &x_offset, &y_offset);
|
||||
if (clutter_actor_get_paint_box (fbo_source, &box))
|
||||
clutter_actor_box_get_origin (&box, &x_offset, &y_offset);
|
||||
else
|
||||
{
|
||||
/* As a fallback when the paint box can't be determined we use
|
||||
* the transformed allocation to come up with an offset instead.
|
||||
*
|
||||
* FIXME: when we don't have a paint box we should instead be
|
||||
* falling back to a stage sized fbo with an offset of (0,0)
|
||||
*/
|
||||
|
||||
ClutterVertex verts[4];
|
||||
float x_min = G_MAXFLOAT, y_min = G_MAXFLOAT;
|
||||
int i;
|
||||
|
||||
/* Get the actors allocation transformed into screen coordinates.
|
||||
*
|
||||
* XXX: Note: this may not be a bounding box for the actor, since an
|
||||
* actor with depth may escape the box due to its perspective
|
||||
* projection. */
|
||||
clutter_actor_get_abs_allocation_vertices (fbo_source, verts);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (verts); ++i)
|
||||
{
|
||||
if (verts[i].x < x_min)
|
||||
x_min = verts[i].x;
|
||||
if (verts[i].y < y_min)
|
||||
y_min = verts[i].y;
|
||||
}
|
||||
|
||||
/* XXX: It's not good enough to round by simply truncating the fraction here
|
||||
* via a cast, as it results in offscreen rendering being offset by 1 pixel
|
||||
* in many cases... */
|
||||
#define ROUND(x) ((x) >= 0 ? (long)((x) + 0.5) : (long)((x) - 0.5))
|
||||
|
||||
x_offset = ROUND (x_min);
|
||||
y_offset = ROUND (y_min);
|
||||
|
||||
#undef ROUND
|
||||
}
|
||||
|
||||
/* translate the viewport so that the source actor lands on the
|
||||
* sub-region backed by the offscreen framebuffer... */
|
||||
@ -432,7 +470,7 @@ update_fbo (ClutterActor *self)
|
||||
ClutterMainContext *context;
|
||||
ClutterShader *shader = NULL;
|
||||
ClutterActor *stage = NULL;
|
||||
ClutterPerspective perspective;
|
||||
CoglMatrix projection;
|
||||
CoglColor transparent_col;
|
||||
|
||||
context = _clutter_context_get_default ();
|
||||
@ -466,24 +504,21 @@ update_fbo (ClutterActor *self)
|
||||
* under the actor.
|
||||
*/
|
||||
|
||||
clutter_stage_get_perspective (CLUTTER_STAGE (stage), &perspective);
|
||||
_clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
|
||||
|
||||
/* Set the projection matrix modelview matrix as it is for the
|
||||
* stage... */
|
||||
cogl_set_projection_matrix (&projection);
|
||||
|
||||
clutter_actor_get_size (stage, &stage_width, &stage_height);
|
||||
|
||||
/* Set the projection matrix modelview matrix and viewport size as
|
||||
* they are for the stage... */
|
||||
_cogl_setup_viewport (stage_width, stage_height,
|
||||
perspective.fovy,
|
||||
perspective.aspect,
|
||||
perspective.z_near,
|
||||
perspective.z_far);
|
||||
|
||||
/* Negatively offset the viewport so that the offscreen framebuffer is
|
||||
* position underneath the fbo_source actor... */
|
||||
/* Set a negatively offset the viewport so that the offscreen
|
||||
* framebuffer is position underneath the fbo_source actor... */
|
||||
set_viewport_with_buffer_under_fbo_source (priv->fbo_source,
|
||||
stage_width,
|
||||
stage_height);
|
||||
|
||||
/* Reapply the source's parent transformations */
|
||||
/* Apply the source's parent transformations to the modelview */
|
||||
if ((source_parent = clutter_actor_get_parent (priv->fbo_source)))
|
||||
{
|
||||
CoglMatrix modelview;
|
||||
@ -2315,9 +2350,26 @@ on_fbo_source_size_change (GObject *object,
|
||||
ClutterTexturePrivate *priv = texture->priv;
|
||||
gfloat w, h;
|
||||
ClutterActorBox box;
|
||||
gboolean status;
|
||||
|
||||
clutter_actor_get_paint_box (priv->fbo_source, &box);
|
||||
clutter_actor_box_get_size (&box, &w, &h);
|
||||
status = clutter_actor_get_paint_box (priv->fbo_source, &box);
|
||||
if (status)
|
||||
clutter_actor_box_get_size (&box, &w, &h);
|
||||
|
||||
/* In the end we will size the framebuffer according to the paint
|
||||
* box, but for code that does:
|
||||
* tex = clutter_texture_new_from_actor (src);
|
||||
* clutter_actor_get_size (tex, &width, &height);
|
||||
* it seems more helpfull to return the src actor size if it has a
|
||||
* degenerate paint box. The most likely reason it will have a
|
||||
* degenerate paint box is simply that the src currently has no
|
||||
* parent. */
|
||||
if (status == FALSE || w == 0 || h == 0)
|
||||
clutter_actor_get_size (priv->fbo_source, &w, &h);
|
||||
|
||||
/* We can't create a texture with a width or height of 0... */
|
||||
w = MAX (1, w);
|
||||
h = MAX (1, h);
|
||||
|
||||
if (w != priv->image_width || h != priv->image_height)
|
||||
{
|
||||
@ -2458,6 +2510,7 @@ clutter_texture_new_from_actor (ClutterActor *actor)
|
||||
ClutterTexturePrivate *priv;
|
||||
gfloat w, h;
|
||||
ClutterActorBox box;
|
||||
gboolean status;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
|
||||
|
||||
@ -2472,13 +2525,25 @@ clutter_texture_new_from_actor (ClutterActor *actor)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
clutter_actor_get_paint_box (actor, &box);
|
||||
clutter_actor_box_get_size (&box, &w, &h);
|
||||
status = clutter_actor_get_paint_box (actor, &box);
|
||||
if (status)
|
||||
clutter_actor_box_get_size (&box, &w, &h);
|
||||
|
||||
/* In the end we will size the framebuffer according to the paint
|
||||
* box, but for code that does:
|
||||
* tex = clutter_texture_new_from_actor (src);
|
||||
* clutter_actor_get_size (tex, &width, &height);
|
||||
* it seems more helpfull to return the src actor size if it has a
|
||||
* degenerate paint box. The most likely reason it will have a
|
||||
* degenerate paint box is simply that the src currently has no
|
||||
* parent. */
|
||||
if (status == FALSE || w == 0 || h == 0)
|
||||
clutter_actor_get_size (actor, &w, &h);
|
||||
|
||||
/* We can't create a 0x0 fbo so always bump the size up to at least
|
||||
* 1 */
|
||||
w = MAX(1,w);
|
||||
h = MAX(1,h);
|
||||
w = MAX (1, w);
|
||||
h = MAX (1, h);
|
||||
|
||||
/* Hopefully now were good.. */
|
||||
texture = g_object_new (CLUTTER_TYPE_TEXTURE,
|
||||
|
@ -91,6 +91,22 @@ typedef struct _ClutterActorBox ClutterActorBox;
|
||||
typedef struct _ClutterGeometry ClutterGeometry;
|
||||
typedef struct _ClutterKnot ClutterKnot;
|
||||
typedef struct _ClutterVertex ClutterVertex;
|
||||
|
||||
/**
|
||||
* ClutterPaintVolume:
|
||||
*
|
||||
* <structname>ClutterPaintVolume</structname> is an opaque structure
|
||||
* whose members cannot be directly accessed.
|
||||
*
|
||||
* A <structname>ClutterPaintVolume</structname> represents an
|
||||
* a bounding volume whos internal representation isn't defined but
|
||||
* can be set and queried in terms of an axis aligned bounding box.
|
||||
*
|
||||
* Other internal representation and methods for describing the
|
||||
* bounding volume may be added in the future.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
typedef struct _ClutterPaintVolume ClutterPaintVolume;
|
||||
|
||||
/**
|
||||
@ -456,6 +472,8 @@ gfloat clutter_paint_volume_get_height (const ClutterPaintVolume *p
|
||||
void clutter_paint_volume_set_depth (ClutterPaintVolume *pv,
|
||||
gfloat depth);
|
||||
gfloat clutter_paint_volume_get_depth (const ClutterPaintVolume *pv);
|
||||
void clutter_paint_volume_union (ClutterPaintVolume *pv,
|
||||
const ClutterPaintVolume *another_pv);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -359,7 +359,7 @@ _clutter_stage_egl_redraw (ClutterStageEGL *stage_egl,
|
||||
egl_surface = backend_egl->egl_surface;
|
||||
#endif
|
||||
|
||||
clutter_actor_paint (wrapper);
|
||||
_clutter_stage_do_paint (CLUTTER_STAGE (wrapper));
|
||||
cogl_flush ();
|
||||
|
||||
eglSwapBuffers (backend_egl->edpy, egl_surface);
|
||||
|
@ -71,7 +71,7 @@ clutter_backend_egl_redraw (ClutterBackend *backend,
|
||||
stage_egl = CLUTTER_STAGE_EGL (impl);
|
||||
|
||||
eglWaitNative (EGL_CORE_NATIVE_ENGINE);
|
||||
clutter_actor_paint (CLUTTER_ACTOR (stage));
|
||||
_clutter_stage_do_paint (stage);
|
||||
cogl_flush ();
|
||||
eglWaitGL();
|
||||
eglSwapBuffers (backend_egl->edpy, stage_egl->egl_surface);
|
||||
|
@ -532,11 +532,11 @@ _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
|
||||
stage_glx->bounding_redraw_clip.y,
|
||||
stage_glx->bounding_redraw_clip.width,
|
||||
stage_glx->bounding_redraw_clip.height);
|
||||
clutter_actor_paint (CLUTTER_ACTOR (stage));
|
||||
_clutter_stage_do_paint (stage);
|
||||
cogl_clip_pop ();
|
||||
}
|
||||
else
|
||||
clutter_actor_paint (CLUTTER_ACTOR (stage));
|
||||
_clutter_stage_do_paint (stage);
|
||||
|
||||
cogl_flush ();
|
||||
CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer);
|
||||
|
@ -147,7 +147,7 @@ clutter_stage_osx_get_wrapper (ClutterStageWindow *stage_window);
|
||||
|
||||
- (void) drawRect: (NSRect) bounds
|
||||
{
|
||||
clutter_actor_paint (CLUTTER_ACTOR (self->stage_osx->wrapper));
|
||||
_clutter_stage_do_paint (CLUTTER_STAGE (self->stage_osx->wrapper));
|
||||
cogl_flush ();
|
||||
[[self openGLContext] flushBuffer];
|
||||
}
|
||||
|
@ -494,7 +494,7 @@ clutter_backend_win32_redraw (ClutterBackend *backend,
|
||||
stage_win32 = CLUTTER_STAGE_WIN32 (impl);
|
||||
|
||||
/* this will cause the stage implementation to be painted */
|
||||
clutter_actor_paint (CLUTTER_ACTOR (stage));
|
||||
_clutter_stage_do_paint (stage);
|
||||
cogl_flush ();
|
||||
|
||||
if (stage_win32->client_dc)
|
||||
|
Loading…
Reference in New Issue
Block a user