[gtk+/wip/baedert/gl: 1/11] gl renderer: draw all outset shadows



commit 2bc10fa365150bbb72dea999d7532f83fb8b926e
Author: Timm Bäder <mail baedert org>
Date:   Thu Dec 28 16:41:32 2017 +0100

    gl renderer: draw all outset shadows
    
    Instead of falling back to cairo for most of them.

 gsk/gl/gskglrenderer.c                   |  250 +++++++++++++++++-------------
 gsk/gl/gskglrenderopsprivate.h           |    2 +
 gsk/resources/glsl/blur.fs.glsl          |   53 +++----
 gsk/resources/glsl/outset_shadow.fs.glsl |    4 +-
 4 files changed, 171 insertions(+), 138 deletions(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index ea5bb02..ee3b625 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -13,6 +13,7 @@
 #include "gskglglyphcacheprivate.h"
 #include "gdk/gdktextureprivate.h"
 #include "gskglrenderopsprivate.h"
+#include "gskcairoblurprivate.h"
 
 #include "gskprivate.h"
 
@@ -874,15 +875,15 @@ render_outset_shadow_node (GskGLRenderer       *self,
   const GskRoundedRect *outline = gsk_outset_shadow_node_peek_outline (node);
   GskRoundedRect offset_outline;
   const float blur_radius = gsk_outset_shadow_node_get_blur_radius (node);
+  const float blur_extra = gsk_cairo_blur_compute_pixels (blur_radius);
   const float spread = gsk_outset_shadow_node_get_spread (node);
   const float dx = gsk_outset_shadow_node_get_dx (node);
   const float dy = gsk_outset_shadow_node_get_dy (node);
-  const float min_x = outline->bounds.origin.x - spread - blur_radius;
-  const float min_y = outline->bounds.origin.y - spread - blur_radius;
-  const float max_x = min_x + outline->bounds.size.width  + (spread+blur_radius) * 2;
-  const float max_y = min_y + outline->bounds.size.height + (spread +blur_radius) * 2;
+  const float min_x = outline->bounds.origin.x - spread - blur_extra / 2.0;
+  const float min_y = outline->bounds.origin.y - spread - blur_extra / 2.0;
+  const float max_x = min_x + outline->bounds.size.width  + (spread + blur_extra/2.0) * 2;
+  const float max_y = min_y + outline->bounds.size.height + (spread + blur_extra/2.0) * 2;
   float texture_width, texture_height;
-  int i;
   RenderOp op;
   graphene_matrix_t identity;
   graphene_matrix_t prev_projection;
@@ -897,28 +898,22 @@ render_outset_shadow_node (GskGLRenderer       *self,
   /* offset_outline is the minimal outline we need to draw the given drop shadow,
    * enlarged by the spread and offset by the blur radius. */
   offset_outline = *outline;
+  /* Shrink our outline to the minimum size that can still hold all the border radii */
   gsk_rounded_rect_shrink_to_minimum (&offset_outline);
+  /* Increase by the spread */
   gsk_rounded_rect_shrink (&offset_outline, -spread, -spread, -spread, -spread);
+  /* No we need to incorporate the blur radius; since we blur an edge an equal blur_extra/2.0
+   * on both sides, the minimum side of both width and height needs to be blur_extra */
+  offset_outline.bounds.size.width = MAX (offset_outline.bounds.size.width, blur_extra);
+  offset_outline.bounds.size.height = MAX (offset_outline.bounds.size.height, blur_extra);
+  /* For the center part, we add a few pixels */
   offset_outline.bounds.size.width += SHADOW_EXTRA_SIZE;
   offset_outline.bounds.size.height += SHADOW_EXTRA_SIZE;
-  offset_outline.bounds.origin.x = blur_radius;
-  offset_outline.bounds.origin.y = blur_radius;
+  offset_outline.bounds.origin.x = blur_extra / 2.0f;
+  offset_outline.bounds.origin.y = blur_extra / 2.0f;
 
-  texture_width = offset_outline.bounds.size.width   + (blur_radius * 2);
-  texture_height = offset_outline.bounds.size.height + (blur_radius * 2);
-
-  /* TODO: Find out if this happens too often.
-   *       Is the condition used here really correct? */
-  for (i = 0; i < 4; i ++)
-    {
-      if (offset_outline.corner[i].width > spread ||
-          offset_outline.corner[i].height > spread)
-        {
-          /*g_warning ("'irregular' box shadow");*/
-          render_fallback_node (self, node, builder, vertex_data);
-          return;
-        }
-    }
+  texture_width = offset_outline.bounds.size.width   + blur_extra;
+  texture_height = offset_outline.bounds.size.height + blur_extra;
 
   texture_id = gsk_gl_driver_create_texture (self->gl_driver, texture_width, texture_height);
   gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
@@ -968,29 +963,42 @@ render_outset_shadow_node (GskGLRenderer       *self,
   if (blur_radius > 0)
     {
       ops_set_program (builder, &self->blur_program);
+      ops_set_clip (builder, &blit_clip);
+      ops_set_texture (builder, texture_id);
       op.op = OP_CHANGE_BLUR;
+      op.blur.dir[0] = 1;
+      op.blur.dir[1] = 0;
       op.blur.size.width = texture_width;
       op.blur.size.height = texture_height;
       op.blur.radius = blur_radius;
       ops_add (builder, &op);
+
+      ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+        { { 0,             0              }, { 0, 1 }, },
+        { { 0,             texture_height }, { 0, 0 }, },
+        { { texture_width, 0              }, { 1, 1 }, },
+
+        { { texture_width, texture_height }, { 1, 0 }, },
+        { { 0,             texture_height }, { 0, 0 }, },
+        { { texture_width, 0              }, { 1, 1 }, },
+      });
     }
   else
     {
       ops_set_program (builder, &self->blit_program);
+      ops_set_clip (builder, &blit_clip);
+      ops_set_texture (builder, texture_id);
+      ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+        { { 0,             0              }, { 0, 1 }, },
+        { { 0,             texture_height }, { 0, 0 }, },
+        { { texture_width, 0              }, { 1, 1 }, },
+
+        { { texture_width, texture_height }, { 1, 0 }, },
+        { { 0,             texture_height }, { 0, 0 }, },
+        { { texture_width, 0              }, { 1, 1 }, },
+      });
     }
 
-  ops_set_clip (builder, &blit_clip);
-  ops_set_texture (builder, texture_id);
-  ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
-    { { 0,             0              }, { 0, 0 }, },
-    { { 0,             texture_height }, { 0, 1 }, },
-    { { texture_width, 0              }, { 1, 0 }, },
-
-    { { texture_width, texture_height }, { 1, 1 }, },
-    { { 0,             texture_height }, { 0, 1 }, },
-    { { texture_width, 0              }, { 1, 0 }, },
-
-  });
   ops_set_clip (builder, &prev_clip);
 
   ops_set_viewport (builder, &prev_viewport);
@@ -1001,39 +1009,43 @@ render_outset_shadow_node (GskGLRenderer       *self,
   ops_set_program (builder, &self->outset_shadow_program);
   ops_set_texture (builder, blurred_texture_id);
   op.op = OP_CHANGE_OUTSET_SHADOW;
-  rounded_rect_to_floats (self, builder,
-                          gsk_outset_shadow_node_peek_outline (node),
-                          op.outset_shadow.outline,
-                          op.outset_shadow.corner_widths,
-                          op.outset_shadow.corner_heights);
+  {
+    GskRoundedRect offset_outline = *outline;
+
+    graphene_matrix_transform_bounds (&builder->current_modelview, &outline->bounds, &offset_outline.bounds);
+
+    rounded_rect_to_floats (self, builder,
+                            /*outline,*/
+                            &offset_outline,
+                            op.outset_shadow.outline,
+                            op.outset_shadow.corner_widths,
+                            op.outset_shadow.corner_heights);
+  }
   ops_add (builder, &op);
 
   /* We use the one outset shadow op from above to draw all 8 sides/corners. */
   {
     const GskRoundedRect *o = &offset_outline;
-    const struct {
-      float w;
-      float h;
-    } corners[4] = {
-      { MAX (o->corner[0].width,  spread) + blur_radius,
-        MAX (o->corner[0].height, spread) + blur_radius },
-      { MAX (o->corner[1].width,  spread) + blur_radius,
-        MAX (o->corner[1].height, spread) + blur_radius },
-      { MAX (o->corner[2].width,  spread) + blur_radius,
-        MAX (o->corner[2].height, spread) + blur_radius },
-      { MAX (o->corner[3].width,  spread) + blur_radius,
-        MAX (o->corner[3].height, spread) + blur_radius }
-    };
-    float x1 = min_x + dx;
-    float x2 = x1 + corners[0].w - dx;
-    float y1 = min_y + dy;
-    float y2 = y1 + corners[0].h  - dy;
-    float tx1 = 0;
-    float tx2 = ((corners[0].w  - dx) / texture_width);
-    float ty1 = 1 - ((corners[0].h - dy) / texture_height);
-    float ty2 = 1;
+    float top_height = MAX (o->corner[0].height, o->corner[1].height);
+    float bottom_height = MAX (o->corner[2].height, o->corner[3].height);
+    float left_width = MAX (o->corner[0].width, o->corner[3].width);
+    float right_width = MAX (o->corner[1].width, o->corner[2].width);
+    float x1, x2, y1, y2, tx1, tx2, ty1, ty2;
+
+    top_height    = MAX (top_height,    blur_extra / 2.0f) + (blur_extra / 2.0f);
+    bottom_height = MAX (bottom_height, blur_extra / 2.0f) + (blur_extra / 2.0f);
+    left_width    = MAX (left_width,    blur_extra / 2.0f) + (blur_extra / 2.0f);
+    right_width   = MAX (right_width,   blur_extra / 2.0f) + (blur_extra / 2.0f);
 
     /* Top left */
+    x1 = min_x + dx;
+    x2 = min_x + dx + left_width;
+    y1 = min_y + dy;
+    y2 = min_y + dy + top_height;
+    tx1 = 0;
+    tx2 = left_width / texture_width;
+    ty1 = 1 - (top_height / texture_height);
+    ty2 = 1;
     ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
       { { x1, y1 }, { tx1, ty2 }, },
       { { x1, y2 }, { tx1, ty1 }, },
@@ -1045,13 +1057,13 @@ render_outset_shadow_node (GskGLRenderer       *self,
     });
 
     /* Top right */
-    x1 = max_x - corners[1].w ;
-    x2 = x1 + corners[1].w  + dx;
+    x1 = max_x + dx - right_width;
+    x2 = max_x + dx;
     y1 = min_y + dy;
-    y2 = y1 + corners[1].h  - dy;
-    tx1 = 1 - ((corners[1].w  + dx) / texture_width);
+    y2 = min_y + dy + top_height;
+    tx1 = 1 - (right_width / texture_width);
     tx2 = 1;
-    ty1 = 1 - ((corners[1].h  - dy) / texture_height);
+    ty1 = 1 - (top_height / texture_height);
     ty2 = 1;
     ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
       { { x1, y1 }, { tx1, ty2 }, },
@@ -1064,14 +1076,14 @@ render_outset_shadow_node (GskGLRenderer       *self,
     });
 
     /* Bottom right */
-    x1 = max_x - corners[2].w ;
-    x2 = x1 + corners[2].w  + dx;
-    y1 = max_y - corners[2].h ;
-    y2 = y1 + corners[2].h  + dy;
-    tx1 = 1 - ((corners[2].w  + dx) / texture_width);
+    x1 = max_x + dx - right_width;
+    x2 = max_x + dx;
+    y1 = max_y + dy - bottom_height;
+    y2 = max_y + dy;
+    tx1 = 1 - (right_width / texture_width);
     tx2 = 1;
     ty1 = 0;
-    ty2 = (corners[2].h  + dy) / texture_height;
+    ty2 = (bottom_height / texture_height);
     ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
       { { x1, y1 }, { tx1, ty2 }, },
       { { x1, y2 }, { tx1, ty1 }, },
@@ -1084,13 +1096,13 @@ render_outset_shadow_node (GskGLRenderer       *self,
 
     /* Bottom left */
     x1 = min_x + dx;
-    x2 = x1 + corners[3].w  - dx;
-    y1 = max_y - corners[3].h ;
-    y2 = y1 + corners[3].h + dy;
+    x2 = min_x + dx + left_width;
+    y1 = max_y + dy - bottom_height;
+    y2 = max_y + dy;
     tx1 = 0;
-    tx2 = (corners[3].w  - dx) / texture_width;
+    tx2 = left_width / texture_width;
     ty1 = 0;
-    ty2 = (corners[3].h  + dy) / texture_height;
+    ty2 = bottom_height / texture_height;
     ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
       { { x1, y1 }, { tx1, ty2 }, },
       { { x1, y2 }, { tx1, ty1 }, },
@@ -1103,13 +1115,13 @@ render_outset_shadow_node (GskGLRenderer       *self,
 
     /* Left side */
     x1 = min_x + dx;
-    x2 = x1 + corners[0].w - dx;
-    y1 = min_y + corners[0].h;
-    y2 = max_y - corners[3].h;
+    x2 = min_x + dx + left_width;
+    y1 = min_y + dy + top_height;
+    y2 = max_y + dy - bottom_height;
     tx1 = 0;
-    tx2 = (x2 - x1) / texture_width;
-    ty1 = 1 - (corners[0].h / texture_height);
-    ty2 = ty1 - (SHADOW_EXTRA_SIZE / texture_height);
+    tx2 = left_width / texture_width;
+    ty1 = 0.5f - SHADOW_EXTRA_SIZE / 2.0f / texture_height;
+    ty2 = ty1 + (SHADOW_EXTRA_SIZE / texture_height);
     ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
       { { x1, y1 }, { tx1, ty2 }, },
       { { x1, y2 }, { tx1, ty1 }, },
@@ -1121,14 +1133,14 @@ render_outset_shadow_node (GskGLRenderer       *self,
     });
 
     /* Right side */
-    x1 = max_x - spread - blur_radius;
+    x1 = max_x + dx - right_width;
     x2 = max_x + dx;
-    y1 = min_y + corners[0].h;
-    y2 = max_y - corners[3].h;
-    tx1 = 1 - ((x2 - x1) / texture_width);
+    y1 = min_y + dy + top_height;
+    y2 = max_y + dy - bottom_height;
+    tx1 = 1 - (right_width / texture_width);
     tx2 = 1;
-    ty1 = 1 - (corners[1].h) / texture_height;
-    ty2 = ty1 - (SHADOW_EXTRA_SIZE / texture_height);
+    ty1 = 0.5f - SHADOW_EXTRA_SIZE / 2.0f / texture_height;
+    ty2 = ty1 + (SHADOW_EXTRA_SIZE / texture_height);
     ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
       { { x1, y1 }, { tx1, ty2 }, },
       { { x1, y2 }, { tx1, ty1 }, },
@@ -1140,33 +1152,52 @@ render_outset_shadow_node (GskGLRenderer       *self,
     });
 
     /* Top side */
-    x1 = min_x + corners[0].w;
-    x2 = max_x - corners[1].w;
+    x1 = min_x + dx + left_width;
+    x2 = max_x + dx - right_width;
     y1 = min_y + dy;
-    y2 = y1 + spread + blur_radius - dy;
-    tx1 = corners[1].w / texture_width;
+    y2 = min_y + dy + top_height;
+    tx1 = 0.5f - (SHADOW_EXTRA_SIZE / 2.0f / texture_width);
     tx2 = tx1 + (SHADOW_EXTRA_SIZE / texture_width);
-    ty1 = 1;
-    ty2 = 1 - ((y2 - y1) / texture_height);
+    ty1 = 1 - (top_height / texture_height);
+    ty2 = 1;
     ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
-      { { x1, y1 }, { tx1, ty1 }, },
-      { { x1, y2 }, { tx1, ty2 }, },
-      { { x2, y1 }, { tx2, ty1 }, },
+      { { x1, y1 }, { tx1, ty2 }, },
+      { { x1, y2 }, { tx1, ty1 }, },
+      { { x2, y1 }, { tx2, ty2 }, },
 
-      { { x2, y2 }, { tx2, ty2 }, },
-      { { x1, y2 }, { tx1, ty2 }, },
-      { { x2, y1 }, { tx2, ty1 }, },
+      { { x2, y2 }, { tx2, ty1 }, },
+      { { x1, y2 }, { tx1, ty1 }, },
+      { { x2, y1 }, { tx2, ty2 }, },
     });
 
     /* Bottom side */
-    x1 = min_x + corners[0].w;
-    x2 = max_x - corners[1].w;
-    y1 = max_y - corners[3].h ;
-    y2 = y1 + corners[3].h + dy;
-    tx1 = corners[3].w / texture_width;
+    x1 = min_x + dx + left_width;
+    x2 = max_x + dx - right_width;
+    y1 = max_y + dy - bottom_height;
+    y2 = max_y + dy;
+    tx1 = 0.5f - (SHADOW_EXTRA_SIZE / 2.0f / texture_width);
     tx2 = tx1 + (SHADOW_EXTRA_SIZE / texture_width);
     ty1 = 0;
-    ty2 = (y2 - y1) / texture_height;
+    ty2 = bottom_height / texture_height;
+    ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+      { { x1, y1 }, { tx1, ty2 }, },
+      { { x1, y2 }, { tx1, ty1 }, },
+      { { x2, y1 }, { tx2, ty2 }, },
+
+      { { x2, y2 }, { tx2, ty1 }, },
+      { { x1, y2 }, { tx1, ty1 }, },
+      { { x2, y1 }, { tx2, ty2 }, },
+    });
+
+    /* Middle */
+    x1 = min_x + dx + left_width;
+    x2 = max_x + dx - right_width;
+    y1 = min_y + dy + top_height;
+    y2 = max_y + dy - bottom_height;
+    tx1 = (texture_width - SHADOW_EXTRA_SIZE)  / 2.0f / texture_width;
+    tx2 = (texture_width + SHADOW_EXTRA_SIZE)  / 2.0f / texture_width;
+    ty1 = (texture_height - SHADOW_EXTRA_SIZE) / 2.0f / texture_height;
+    ty2 = (texture_height + SHADOW_EXTRA_SIZE) / 2.0f / texture_height;
     ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
       { { x1, y1 }, { tx1, ty2 }, },
       { { x1, y2 }, { tx1, ty1 }, },
@@ -1176,6 +1207,7 @@ render_outset_shadow_node (GskGLRenderer       *self,
       { { x1, y2 }, { tx1, ty1 }, },
       { { x2, y1 }, { tx2, ty2 }, },
     });
+
   }
 
   ops_set_clip (builder, &prev_clip);
@@ -1550,6 +1582,7 @@ apply_blur_op (const Program  *program,
   OP_PRINT (" -> Blur");
   glUniform1f (program->blur.blur_radius_location, op->blur.radius);
   glUniform2f (program->blur.blur_size_location, op->blur.size.width, op->blur.size.height);
+  /*glUniform2f (program->blur.dir_location, op->blur.dir[0], op->blur.dir[1]);*/
 }
 
 static inline void
@@ -1739,6 +1772,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
   /* blur */
   INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_radius);
   INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_size);
+  /*INIT_PROGRAM_UNIFORM_LOCATION (blur, dir);*/
 
   /* inset shadow */
   INIT_PROGRAM_UNIFORM_LOCATION (inset_shadow, color);
@@ -2268,8 +2302,8 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
           break;
 
         case OP_CHANGE_COLOR:
-          g_assert (program == &self->color_program || program == &self->coloring_program ||
-                    program == &self->shadow_program);
+          /*g_assert (program == &self->color_program || program == &self->coloring_program ||*/
+                    /*program == &self->shadow_program);*/
           apply_color_op (program, op);
           break;
 
diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h
index ff93d67..aaff53c 100644
--- a/gsk/gl/gskglrenderopsprivate.h
+++ b/gsk/gl/gskglrenderopsprivate.h
@@ -79,6 +79,7 @@ typedef struct
     struct {
       int blur_radius_location;
       int blur_size_location;
+      int dir_location;
     } blur;
     struct {
       int color_location;
@@ -138,6 +139,7 @@ typedef struct
     struct {
       float radius;
       graphene_size_t size;
+      float dir[2];
     } blur;
     struct {
       float outline[4];
diff --git a/gsk/resources/glsl/blur.fs.glsl b/gsk/resources/glsl/blur.fs.glsl
index 3ec7d9a..8cf1e28 100644
--- a/gsk/resources/glsl/blur.fs.glsl
+++ b/gsk/resources/glsl/blur.fs.glsl
@@ -1,42 +1,39 @@
+uniform float u_blur_radius = 40.0;
+uniform vec2 u_blur_size = vec2(393, 393);
 
-uniform float u_blur_radius = 4.0;
-uniform vec2 u_blur_size;
-
-const int   samples_x    = 15;  // must be odd
-const int   samples_y    = 15;  // must be odd
-
-const int   half_samples_x = samples_x / 2;
-const int   half_samples_y = samples_y / 2;
-
-float Gaussian (float sigma, float x)
-{
+float Gaussian (float sigma, float x) {
   return exp ( - (x * x) / (2.0 * sigma * sigma));
 }
 
-vec4 blur_pixel (in vec2 uv)
-{
+vec4 blur_pixel (in vec2 uv) {
   float total = 0.0;
   vec4 ret = vec4 (0);
   float pixel_size_x = (1.0 / u_blur_size.x);
   float pixel_size_y = (1.0 / u_blur_size.y);
 
-  for (int y = 0; y < samples_y; ++y)
-    {
-      float fy = Gaussian (u_blur_radius, float(y) - float(half_samples_x));
-      float offset_y = float(y - half_samples_y) * pixel_size_y;
-      for (int x = 0; x < samples_x; ++x)
-        {
-          float fx = Gaussian (u_blur_radius, float(x) - float(half_samples_x));
-          float offset_x = float(x - half_samples_x) * pixel_size_x;
-          total += fx * fy;
-          ret += Texture(u_source, uv + vec2(offset_x, offset_y)) * fx * fy;
-        }
+  // XXX The magic value here is GAUSSIAN_SCALE_FACTOR from gskcairoblur.c
+  float radius = u_blur_radius  * 2.30348;
+
+  int half_radius = int(radius / 2.0);
+
+  for (int y = -half_radius; y < half_radius; y ++) {
+    float fy = Gaussian (radius / 2.0, float(y));
+    float offset_y = y * pixel_size_x;
+
+    for (int x = -half_radius; x < half_radius; x ++) {
+      float fx = Gaussian (radius / 2.0, float(x));
+      float offset_x = x * pixel_size_x;
+
+      vec4 c = Texture(u_source, uv + vec2(offset_x, offset_y));
+      total += fx * fy;
+      ret += c * fx * fy;
     }
+  }
+
   return ret / total;
 }
 
-void main()
-{
-  /*color = clip (inPos, blur_pixel (inTexCoord));*/
-  setOutputColor(blur_pixel(vUv));
+void main() {
+  vec4 color = blur_pixel(vUv);
+  setOutputColor(color);
 }
diff --git a/gsk/resources/glsl/outset_shadow.fs.glsl b/gsk/resources/glsl/outset_shadow.fs.glsl
index 997891c..fcd1c42 100644
--- a/gsk/resources/glsl/outset_shadow.fs.glsl
+++ b/gsk/resources/glsl/outset_shadow.fs.glsl
@@ -15,6 +15,6 @@ void main() {
   RoundedRect outline = RoundedRect(vec4(u_outline.xy, u_outline.xy + u_outline.zw), u_corner_widths, 
u_corner_heights);
 
   vec4 color = Texture(u_source, vUv);
-  color *= (1 - clamp(rounded_rect_coverage (outline, f.xy), 0, 1));
-  setOutputColor(color);
+  color = color * (1 -  clamp(rounded_rect_coverage (outline, f.xy), 0, 1));
+  setOutputColor(color * u_alpha);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]