diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 2e418a8e7..565392637 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -457,7 +457,7 @@ struct _ClutterActorPrivate * of the QUEUE_REDRAW signal. It's an out-of-band argument. * See clutter_actor_queue_clipped_redraw() for details. */ - const ClutterActorBox *oob_queue_redraw_clip; + const ClutterPaintVolume *oob_queue_redraw_clip; ClutterMetaGroup *actions; ClutterMetaGroup *constraints; @@ -4907,7 +4907,7 @@ _clutter_actor_get_allocation_clip (ClutterActor *self, ClutterActorBox allocation; /* XXX: we don't care if we get an out of date allocation here - * because clutter_actor_queue_redraw_with_origin knows to ignore + * because clutter_actor_queue_redraw_with_clip knows to ignore * the clip if the actor's allocation is invalid. * * This is noted because clutter_actor_get_allocation_box does some @@ -4917,7 +4917,7 @@ _clutter_actor_get_allocation_clip (ClutterActor *self, */ clutter_actor_get_allocation_box (self, &allocation); - /* NB: clutter_actor_queue_clipped_redraw expects a box in the + /* NB: clutter_actor_queue_redraw_with_clip expects a box in the * actor's own coordinate space but the allocation is in parent * coordinates */ clip->x1 = 0; @@ -4931,7 +4931,7 @@ _clutter_actor_get_allocation_clip (ClutterActor *self, * @self: A #ClutterActor * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of * this queue redraw. - * @clip: A #ClutterActorBox describing the bounds of what needs to be + * @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. * @@ -4939,21 +4939,16 @@ _clutter_actor_get_allocation_clip (ClutterActor *self, * occurs once the main loop becomes idle (after the current batch of * events has been processed, roughly). * - * If the %CLUTTER_REDRAW_CLIPPED_TO_BOX @flag is used, the clip box is + * If no flags are given the clip volume is defined by @volume * specified in actor coordinates and tells Clutter that only content - * within this box has been changed so Clutter can optionally optimize - * the redraw. + * within this volume has been changed so Clutter can optionally + * optimize the redraw. * - * If you are queuing a clipped redraw it is assumed that the actor is - * flat, and once the clip rectangle is projected into stage - * coordinates it will cover the area of the stage that needs to be - * redrawn. This is not possible to determine for 3D actors since the - * projection of such actors may escape the clip rectangle. - * - * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @clip - * should be NULL and this tells Clutter to use the actors current - * allocation as a clip box. As above this flag can only be used for - * 2D actors. + * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume + * should be %NULL and this tells Clutter to use the actor's current + * allocation as a clip box. This flag can only be used for 2D actors, + * because any actor with depth may be projected outside its + * allocation. * * Applications rarely need to call this, as redraws are handled * automatically by modification functions. @@ -4963,16 +4958,25 @@ _clutter_actor_get_allocation_clip (ClutterActor *self, * * Also be aware that painting is a NOP for actors with an opacity of * 0 + * + * When you are implementing a custom actor you must queue a redraw + * whenever some private state changes that will affect painting or + * picking of your actor. */ void _clutter_actor_queue_redraw_with_clip (ClutterActor *self, ClutterRedrawFlags flags, - ClutterActorBox *clip) + ClutterPaintVolume *volume) { - ClutterActorBox allocation_clip; + ClutterPaintVolume allocation_pv; + ClutterPaintVolume *pv; + gboolean should_free_pv; /* If the actor doesn't have a valid allocation then we will queue a - * full stage redraw */ + * full stage redraw. + * + * XXX: Is this check redundant? Or should it maybe only be done + * when flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION? */ if (self->priv->needs_allocation) { clutter_actor_queue_redraw (self); @@ -4981,16 +4985,37 @@ _clutter_actor_queue_redraw_with_clip (ClutterActor *self, if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION) { + ClutterActorBox allocation_clip; + ClutterVertex origin; + + _clutter_paint_volume_init_static (self, &allocation_pv); + pv = &allocation_pv; + _clutter_actor_get_allocation_clip (self, &allocation_clip); - clip = &allocation_clip; + + origin.x = allocation_clip.x1; + origin.y = allocation_clip.y1; + origin.z = 0; + clutter_paint_volume_set_origin (pv, &origin); + clutter_paint_volume_set_width (pv, + allocation_clip.x2 - allocation_clip.x1); + clutter_paint_volume_set_height (pv, + allocation_clip.y2 - + allocation_clip.y1); + should_free_pv = TRUE; + } + else + { + pv = volume; + should_free_pv = FALSE; } - /* XXX: Ideally the redraw signal would take a clip rectangle + /* XXX: Ideally the redraw signal would take a clip volume * argument, but that would be an ABI break. Until we can break the * ABI we pass the argument out-of-band via an actor->priv member... */ - _clutter_actor_set_queue_redraw_clip (self, clip); + _clutter_actor_set_queue_redraw_clip (self, pv); clutter_actor_queue_redraw_with_origin (self, self); @@ -5001,6 +5026,9 @@ _clutter_actor_queue_redraw_with_clip (ClutterActor *self, * Note: A NULL clip denotes a full-stage, un-clipped redraw */ _clutter_actor_set_queue_redraw_clip (self, NULL); + + if (should_free_pv) + clutter_paint_volume_free (pv); } /** @@ -10895,7 +10923,7 @@ clutter_actor_has_pointer (ClutterActor *self) * the QUEUE_REDRAW signal. It is an out-of-band argument. See * clutter_actor_queue_clipped_redraw() for details. */ -const ClutterActorBox * +const ClutterPaintVolume * _clutter_actor_get_queue_redraw_clip (ClutterActor *self) { return self->priv->oob_queue_redraw_clip; @@ -10903,7 +10931,7 @@ _clutter_actor_get_queue_redraw_clip (ClutterActor *self) void _clutter_actor_set_queue_redraw_clip (ClutterActor *self, - const ClutterActorBox *clip) + const ClutterPaintVolume *clip) { self->priv->oob_queue_redraw_clip = clip; } diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index cea8c4b10..59f983fd8 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -136,25 +136,6 @@ typedef enum CLUTTER_ABSOLUTE_ORIGIN_CHANGED = 1 << 1 } ClutterAllocationFlags; -/** - * ClutterRedrawFlags: - * @CLUTTER_REDRAW_CLIPPED_TO_BOX: Tells clutter the redraw is clipped - * to a given clip box in actor coordinates. - * @CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION: Tells clutter the maximum - * extents of what needs to be redrawn lies within the actors - * current allocation. - * - * Flags passed to the clutter_actor_queue_redraw_with_clip () - * function - * - * Since: 1.2 - */ -typedef enum -{ - CLUTTER_REDRAW_CLIPPED_TO_BOX = 0, - CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION = 1 << 1 -} ClutterRedrawFlags; - /** * ClutterActor: * @flags: #ClutterActorFlags diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index 853c9058f..a7725dbda 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -91,6 +91,23 @@ typedef enum { CLUTTER_INTERNAL_CHILD = 1 << 6 } ClutterPrivateFlags; +/* + * ClutterRedrawFlags: + * @CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION: Tells clutter the maximum + * extents of what needs to be redrawn lies within the actors + * current allocation. (Only use this for 2D actors though because + * any actor with depth may be projected outside of its allocation) + * + * Flags passed to the clutter_actor_queue_redraw_with_clip () + * function + * + * Since: 1.6 + */ +typedef enum +{ + CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION = 1 << 0 +} ClutterRedrawFlags; + struct _ClutterInputDevice { GObject parent_instance; @@ -452,10 +469,10 @@ gboolean _clutter_actor_transform_and_project_box (ClutterActor *self, void _clutter_actor_queue_redraw_with_clip (ClutterActor *self, ClutterRedrawFlags flags, - ClutterActorBox *clip); -const ClutterActorBox *_clutter_actor_get_queue_redraw_clip (ClutterActor *self); + ClutterPaintVolume *clip_volume); +const ClutterPaintVolume *_clutter_actor_get_queue_redraw_clip (ClutterActor *self); void _clutter_actor_set_queue_redraw_clip (ClutterActor *self, - const ClutterActorBox *clip); + const ClutterPaintVolume *clip_volume); void _clutter_run_repaint_functions (void); diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 794a4fb09..521c3ec7f 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -729,10 +729,10 @@ clutter_stage_real_queue_redraw (ClutterActor *actor, ClutterStagePrivate *priv = stage->priv; ClutterStageWindow *stage_window; ClutterGeometry stage_clip; - const ClutterActorBox *clip; - ClutterActorBox bounds; - ClutterVertex v[4]; - int i; + const ClutterPaintVolume *redraw_clip; + ClutterPaintVolume projected_clip; + CoglMatrix modelview; + ClutterActorBox bounding_box; CLUTTER_NOTE (PAINT, "Redraw request number %lu", CLUTTER_CONTEXT ()->redraw_count + 1); @@ -761,47 +761,50 @@ clutter_stage_real_queue_redraw (ClutterActor *actor, /* If the backend can't do anything with redraw clips (e.g. it already knows * it needs to redraw everything anyway) then don't spend time transforming - * any clip regions into stage coordinates... */ + * any clip volume into stage coordinates... */ stage_window = _clutter_stage_get_window (stage); if (_clutter_stage_window_ignoring_redraw_clips (stage_window)) return; - /* Convert the clip rectangle (which is in leaf actor coordinates) into stage + /* Convert the clip volume (which is in leaf actor coordinates) into stage * coordinates and then into an axis aligned stage coordinates bounding * box... */ - clip = _clutter_actor_get_queue_redraw_clip (leaf); - if (!clip) + if (!_clutter_actor_get_queue_redraw_clip (leaf)) { _clutter_stage_window_add_redraw_clip (stage_window, NULL); return; } - _clutter_actor_transform_and_project_box (leaf, clip, v); + redraw_clip = _clutter_actor_get_queue_redraw_clip (leaf); - bounds.x1 = v[0].x; bounds.y1 = v[0].y; - bounds.x2 = v[0].x; bounds.y2 = v[0].y; + _clutter_paint_volume_copy_static (redraw_clip, &projected_clip); - for (i = 0; i < 4; i++) - { - if (v[i].x < bounds.x1) - bounds.x1 = v[i].x; - else if (v[i].x > bounds.x2) - bounds.x2 = v[i].x; + /* NB: _clutter_actor_apply_modelview_transform_recursive will never + * include the transformation between stage coordinates and OpenGL + * window coordinates, we have to explicitly use the + * stage->apply_transform to get that... */ + cogl_matrix_init_identity (&modelview); + _clutter_actor_apply_modelview_transform (CLUTTER_ACTOR (stage), &modelview); + _clutter_actor_apply_modelview_transform_recursive (leaf, NULL, &modelview); - if (v[i].y < bounds.y1) - bounds.y1 = v[i].y; - else if (v[i].y > bounds.y2) - bounds.y2 = v[i].y; - } + _clutter_paint_volume_project (&projected_clip, + &modelview, + &priv->projection, + priv->viewport); + + _clutter_paint_volume_get_bounding_box (&projected_clip, &bounding_box); + clutter_paint_volume_free (&projected_clip); + + clutter_actor_box_clamp_to_pixel (&bounding_box); /* when converting to integer coordinates make sure we round the edges of the * clip rectangle outwards... */ - stage_clip.x = bounds.x1; - stage_clip.y = bounds.y1; - stage_clip.width = ceilf (bounds.x2) - stage_clip.x; - stage_clip.height = ceilf (bounds.y2) - stage_clip.y; + stage_clip.x = bounding_box.x1; + stage_clip.y = bounding_box.y1; + stage_clip.width = bounding_box.x2 - stage_clip.x; + stage_clip.height = bounding_box.y2 - stage_clip.y; _clutter_stage_window_add_redraw_clip (stage_window, &stage_clip); } diff --git a/clutter/x11/clutter-x11-texture-pixmap.c b/clutter/x11/clutter-x11-texture-pixmap.c index 2d877e7d6..5f8927f23 100644 --- a/clutter/x11/clutter-x11-texture-pixmap.c +++ b/clutter/x11/clutter-x11-texture-pixmap.c @@ -317,7 +317,8 @@ clutter_x11_texture_pixmap_real_queue_damage_redraw ( ClutterActorBox allocation; float scale_x; float scale_y; - ClutterActorBox clip; + ClutterVertex origin; + ClutterPaintVolume clip; /* NB: clutter_actor_queue_clipped_redraw expects a box in the actor's * coordinate space so we need to convert from pixmap coordinates to @@ -344,14 +345,17 @@ clutter_x11_texture_pixmap_real_queue_damage_redraw ( scale_x = (allocation.x2 - allocation.x1) / priv->pixmap_width; scale_y = (allocation.y2 - allocation.y1) / priv->pixmap_height; - clip.x1 = x * scale_x; - clip.y1 = y * scale_y; - clip.x2 = clip.x1 + width * scale_x; - clip.y2 = clip.y1 + height * scale_y; + _clutter_paint_volume_init_static (self, &clip); - _clutter_actor_queue_redraw_with_clip (self, - CLUTTER_REDRAW_CLIPPED_TO_BOX, - &clip); + origin.x = x * scale_x; + origin.y = y * scale_y; + origin.z = 0; + clutter_paint_volume_set_origin (&clip, &origin); + clutter_paint_volume_set_width (&clip, width * scale_x); + clutter_paint_volume_set_height (&clip, height * scale_y); + + _clutter_actor_queue_redraw_with_clip (self, 0, &clip); + clutter_paint_volume_free (&clip); } static void