[gnome-games] Introduce CairoBlur for blurring cairo surfaces



commit 5c6249d255de3005a24adfd14688fb30904841a3
Author: Neville <nevilleantony98 gmail com>
Date:   Fri Jun 12 09:50:40 2020 +0530

    Introduce CairoBlur for blurring cairo surfaces
    
    The cairo blur logic is reused from GTK's cairoblur.c which blurs window
    shadows.
    
    It will be used in the upcoming commit to blur cover backgrounds.

 src/meson.build           |   1 +
 src/utils/cairo-blur.vala | 118 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+)
---
diff --git a/src/meson.build b/src/meson.build
index d90708c6..c6126e52 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -148,6 +148,7 @@ vala_sources = [
   'ui/titlebar-box.vala',
   'ui/ui-view.vala',
 
+  'utils/cairo-blur.vala',
   'utils/composite-cover.vala',
   'utils/composite-title.vala',
   'utils/cue-sheet/cue-sheet.vala',
diff --git a/src/utils/cairo-blur.vala b/src/utils/cairo-blur.vala
new file mode 100644
index 00000000..16087888
--- /dev/null
+++ b/src/utils/cairo-blur.vala
@@ -0,0 +1,118 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+namespace Games.CairoBlur {
+       public void blur_surface (Cairo.Surface surface, float radius) {
+               if (surface == null)
+                       return;
+
+               if (surface.get_type () != Cairo.SurfaceType.IMAGE)
+                       return;
+
+               var image_surface = (Cairo.ImageSurface) surface;
+               var format = image_surface.get_format ();
+               if (format != Cairo.Format.RGB24 && format != Cairo.Format.ARGB32)
+                       return;
+
+               if (radius == 0)
+                       return;
+
+               /* Before we mess with the surface execute any pending drawing. */
+               surface.flush ();
+               unowned var data = image_surface.get_data ();
+               var width = image_surface.get_width ();
+               var height = image_surface.get_height ();
+               var stride = image_surface.get_stride ();
+
+               exp_blur (data,
+                         width,
+                         height,
+                         stride,
+                         4,
+                         radius,
+                         16,
+                         7);
+
+               /* Inform cairo we altered the surfaces contents. */
+               surface.mark_dirty ();
+       }
+
+       private void exp_blur (uchar[] pixels, int width, int height,
+                              int rowstride, int channels, float radius,
+                              int aprec, int zprec) {
+               /* Calculate the alpha such that 90% of
+               *  the kernel is within the radius.
+               *  (Kernel extends to infinity) */
+               var alpha = (int) ((1 << aprec) * (1.0f - Math.expf (-2.3f / (radius + 1.0f))));
+
+               for (int row = 0; row < height; row++)
+                       blur_row (pixels, width, height,
+                                rowstride, channels, row,
+                                alpha, aprec, zprec);
+
+               for(int col = 0; col < width; col++)
+                       blur_col (pixels, width, height,
+                                 rowstride, channels, col,
+                                 alpha, aprec, zprec);
+       }
+
+       private void blur_row (uchar[] pixels, int width, int height,
+                              int rowstride, int channels, int line,
+                              int alpha, int aprec, int zprec) {
+               var offset = line * rowstride;
+
+               int zR = pixels[offset] << zprec;
+               int zG = pixels[offset + 1] << zprec;
+               int zB = pixels[offset + 2] << zprec;
+               int zA = pixels[offset + 3] << zprec;
+
+               for (int index = 0; index < width; index ++)
+                       blur_inner (pixels, offset + index * channels,
+                                   ref zR, ref zG, ref zB, ref zA,
+                                   alpha, aprec, zprec);
+
+               for (int index = width - 2; index >= 0; index--)
+                       blur_inner (pixels, offset + index * channels,
+                                   ref zR, ref zG, ref zB, ref zA,
+                                   alpha, aprec, zprec);
+       }
+
+       private void blur_col (uchar[] pixels, int width, int height,
+                          int rowstride, int channels, int x,
+                          int alpha, int aprec, int zprec) {
+               var offset = x * channels;
+
+               int zR = pixels [offset] << zprec;
+               int zG = pixels [offset + 1] << zprec;
+               int zB = pixels [offset + 2] << zprec;
+               int zA = pixels [offset + 3] << zprec;
+
+               for (int index = 0; index < height; index++)
+                       blur_inner (pixels, offset + index * rowstride,
+                                   ref zR, ref zG, ref zB, ref zA,
+                                   alpha, aprec, zprec);
+
+               for (int index = height - 2; index >= 0; index--)
+                       blur_inner (pixels, offset + index * rowstride,
+                                   ref zR, ref zG, ref zB, ref zA,
+                                   alpha, aprec, zprec);
+       }
+
+       private void blur_inner (uchar[] pixel, int offset,
+                                ref int zR, ref int zG, ref int zB, ref int zA,
+                                int alpha, int aprec, int zprec) {
+               int R = pixel[offset];
+               int G = pixel[offset + 1];
+               int B = pixel[offset + 2];
+               int A = pixel[offset + 3];
+
+               zR += (alpha * ((R << zprec) - zR)) >> aprec;
+               zG += (alpha * ((G << zprec) - zG)) >> aprec;
+               zB += (alpha * ((B << zprec) - zB)) >> aprec;
+               zA += (alpha * ((A << zprec) - zA)) >> aprec;
+
+               pixel[offset]     = (uchar) (zR >> zprec);
+               pixel[offset + 1] = (uchar) (zG >> zprec);
+               pixel[offset + 2] = (uchar) (zB >> zprec);
+               pixel[offset + 3] = (uchar) (zA >> zprec);
+       }
+}


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