Commit ff08e19f authored by Jonas Ådahl's avatar Jonas Ådahl

shaped-texture: Transform clip and opaque region to texture space

The clip and opaque region are both in a translated stage coordinate
space, where the origin is in the top left corner of the painted
texture. The painting, however, is in the texture coordinate space,
so when the texture is scaled, the coordinate spaces differ.

Handle this by transforming the clip and opaque region to texture
coordinate space before computing the blend region and the opaque region
to paint.

Closes: #300
parent 9c77e52a
......@@ -35,6 +35,7 @@
#include "clutter-utils.h"
#include "meta-texture-tower.h"
#include "region-utils.h"
#include "meta-cullable.h"
......@@ -416,9 +417,14 @@ meta_shaped_texture_paint (ClutterActor *actor)
{
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
MetaShapedTexturePrivate *priv = stex->priv;
double tex_scale;
int tex_width, tex_height;
cairo_rectangle_int_t tex_rect;
guchar opacity;
gboolean use_opaque_region;
cairo_region_t *clip_tex_region;
cairo_region_t *opaque_tex_region;
cairo_region_t *blended_tex_region;
CoglContext *ctx;
CoglFramebuffer *fb;
CoglTexture *paint_tex = NULL;
......@@ -476,6 +482,7 @@ meta_shaped_texture_paint (ClutterActor *actor)
}
}
clutter_actor_get_scale (actor, &tex_scale, NULL);
tex_width = priv->tex_width;
tex_height = priv->tex_height;
......@@ -499,40 +506,61 @@ meta_shaped_texture_paint (ClutterActor *actor)
opacity = clutter_actor_get_paint_opacity (actor);
clutter_actor_get_allocation_box (actor, &alloc);
cairo_region_t *blended_region;
gboolean use_opaque_region = (priv->opaque_region != NULL && opacity == 255);
if (priv->opaque_region && opacity == 255)
{
opaque_tex_region =
meta_region_scale_double (priv->opaque_region,
1.0 / tex_scale,
META_ROUNDING_STRATEGY_SHRINK);
use_opaque_region = TRUE;
}
else
{
use_opaque_region = FALSE;
}
if (priv->clip_region)
{
clip_tex_region =
meta_region_scale_double (priv->clip_region,
1.0 / tex_scale,
META_ROUNDING_STRATEGY_GROW);
}
else
{
clip_tex_region = NULL;
}
if (use_opaque_region)
{
if (priv->clip_region != NULL)
blended_region = cairo_region_copy (priv->clip_region);
if (clip_tex_region)
blended_tex_region = cairo_region_copy (clip_tex_region);
else
blended_region = cairo_region_create_rectangle (&tex_rect);
blended_tex_region = cairo_region_create_rectangle (&tex_rect);
cairo_region_subtract (blended_region, priv->opaque_region);
cairo_region_subtract (blended_tex_region, opaque_tex_region);
}
else
{
if (priv->clip_region != NULL)
blended_region = cairo_region_reference (priv->clip_region);
if (clip_tex_region)
blended_tex_region = cairo_region_reference (clip_tex_region);
else
blended_region = NULL;
blended_tex_region = NULL;
}
/* Limit to how many separate rectangles we'll draw; beyond this just
* fall back and draw the whole thing */
#define MAX_RECTS 16
if (blended_region != NULL)
if (blended_tex_region)
{
int n_rects = cairo_region_num_rectangles (blended_region);
int n_rects = cairo_region_num_rectangles (blended_tex_region);
if (n_rects > MAX_RECTS)
{
/* Fall back to taking the fully blended path. */
use_opaque_region = FALSE;
cairo_region_destroy (blended_region);
blended_region = NULL;
g_clear_pointer (&blended_tex_region, cairo_region_destroy);
}
}
......@@ -544,14 +572,14 @@ meta_shaped_texture_paint (ClutterActor *actor)
int n_rects;
int i;
if (priv->clip_region != NULL)
if (clip_tex_region)
{
region = cairo_region_copy (priv->clip_region);
cairo_region_intersect (region, priv->opaque_region);
region = cairo_region_copy (clip_tex_region);
cairo_region_intersect (region, opaque_tex_region);
}
else
{
region = cairo_region_reference (priv->opaque_region);
region = cairo_region_reference (opaque_tex_region);
}
if (!cairo_region_is_empty (region))
......@@ -575,14 +603,14 @@ meta_shaped_texture_paint (ClutterActor *actor)
/* Now, go ahead and paint the blended parts. */
/* We have three cases:
* 1) blended_region has rectangles - paint the rectangles.
* 2) blended_region is empty - don't paint anything
* 3) blended_region is NULL - paint fully-blended.
* 1) blended_tex_region has rectangles - paint the rectangles.
* 2) blended_tex_region is empty - don't paint anything
* 3) blended_tex_region is NULL - paint fully-blended.
*
* 1) and 3) are the times where we have to paint stuff. This tests
* for 1) and 3).
*/
if (blended_region == NULL || !cairo_region_is_empty (blended_region))
if (!blended_tex_region || !cairo_region_is_empty (blended_tex_region))
{
CoglPipeline *blended_pipeline;
......@@ -604,16 +632,16 @@ meta_shaped_texture_paint (ClutterActor *actor)
cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
cogl_pipeline_set_color (blended_pipeline, &color);
if (blended_region != NULL)
if (blended_tex_region)
{
/* 1) blended_region is not empty. Paint the rectangles. */
/* 1) blended_tex_region is not empty. Paint the rectangles. */
int i;
int n_rects = cairo_region_num_rectangles (blended_region);
int n_rects = cairo_region_num_rectangles (blended_tex_region);
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (blended_region, i, &rect);
cairo_region_get_rectangle (blended_tex_region, i, &rect);
if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
continue;
......@@ -623,7 +651,7 @@ meta_shaped_texture_paint (ClutterActor *actor)
}
else
{
/* 3) blended_region is NULL. Do a full paint. */
/* 3) blended_tex_region is NULL. Do a full paint. */
cogl_framebuffer_draw_rectangle (fb, blended_pipeline,
0, 0,
alloc.x2 - alloc.x1,
......@@ -631,8 +659,7 @@ meta_shaped_texture_paint (ClutterActor *actor)
}
}
if (blended_region != NULL)
cairo_region_destroy (blended_region);
g_clear_pointer (&blended_tex_region, cairo_region_destroy);
}
static void
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment