From a297fb039409733afa7df6eaeb2d28f1af1a93a3 Mon Sep 17 00:00:00 2001 From: Chris Lord Date: Fri, 11 Feb 2011 15:18:08 +0000 Subject: [PATCH] offscreen: Fix partially off-stage actors being clipped in the fbo If an actor was partially off of the stage, it would be clipped because of the stage viewport. This produces problems if you use an offscreen effect that relies on the entire actor being rendered (e.g. shadows). Expand the viewport in this scenario so that the offscreen-rendering isn't clipped. This fixes http://bugzilla.clutter-project.org/show_bug.cgi?id=2550 --- clutter/clutter-offscreen-effect.c | 43 +++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/clutter/clutter-offscreen-effect.c b/clutter/clutter-offscreen-effect.c index db8da6a8e..1fbb17e95 100644 --- a/clutter/clutter-offscreen-effect.c +++ b/clutter/clutter-offscreen-effect.c @@ -196,6 +196,7 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect) CoglMatrix modelview; gfloat fbo_width, fbo_height; gfloat width, height; + gfloat xexpand, yexpand; if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect))) return FALSE; @@ -234,13 +235,53 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect) * framebuffer. */ clutter_actor_get_size (priv->stage, &width, &height); clutter_actor_box_get_origin (&box, &priv->x_offset, &priv->y_offset); - cogl_set_viewport (-priv->x_offset, -priv->y_offset, width, height); + + /* Expand the viewport if the actor is partially off-stage, + * otherwise the actor will end up clipped to the stage viewport + */ + xexpand = 0.f; + if (priv->x_offset < 0.f) + xexpand = -priv->x_offset; + if (priv->x_offset + fbo_width > width) + xexpand = MAX (xexpand, (priv->x_offset + fbo_width) - width); + + yexpand = 0.f; + if (priv->y_offset < 0.f) + yexpand = -priv->y_offset; + if (priv->y_offset + fbo_height > height) + yexpand = MAX (yexpand, (priv->y_offset + fbo_height) - height); + + /* Set the viewport */ + cogl_set_viewport (-(priv->x_offset + xexpand), -(priv->y_offset + yexpand), + width + (2 * xexpand), height + (2 * yexpand)); /* Copy the stage's projection matrix across to the framebuffer */ _clutter_stage_get_projection_matrix (CLUTTER_STAGE (priv->stage), &projection); cogl_set_projection_matrix (&projection); + /* If we've expanded the viewport, make sure to scale the modelview + * matrix accordingly (as it's been initialised to work with the + * original viewport and not our expanded one). + */ + if (xexpand > 0.f || yexpand > 0.f) + { + CoglMatrix correction; + gfloat new_width, new_height; + + new_width = width + (2 * xexpand); + new_height = height + (2 * yexpand); + + cogl_matrix_init_identity (&correction); + cogl_matrix_scale (&correction, + width / new_width, + height / new_height, + 1); + + cogl_matrix_multiply (&correction, &correction, &modelview); + modelview = correction; + } + /* Copy the modelview that would have been used if rendering onscreen */ cogl_set_modelview_matrix (&modelview);