From f9737d78c96a5d9f4566c94702c3ec4a41d9e219 Mon Sep 17 00:00:00 2001 From: Jeremy Attali Date: Sat, 13 Jun 2020 13:18:47 -0400 Subject: [PATCH] feat(blur): add multiple passes logic --- src/render.c | 104 +++++++++++++++++++++++---------------------------- 1 file changed, 47 insertions(+), 57 deletions(-) diff --git a/src/render.c b/src/render.c index 604446a..903865e 100644 --- a/src/render.c +++ b/src/render.c @@ -22,14 +22,13 @@ static cairo_surface_t *blur_surface(cairo_surface_t *surface, double x, int src_width, src_height; int src_stride, dst_stride; guint u, v, w, z; - uint8_t *src, *dst, *tmp; + uint8_t *dst, *tmp; uint32_t *s, *d, p; int i, j, k; const int size = (int)blur_level * 2 + 1; const int half = size / 2; - // const double offset_y = 10.0; gdouble scale_x, scale_y; - guint sum; + guint sum, pass, nb_passes; if (cairo_surface_status(surface)) { return NULL; @@ -37,9 +36,6 @@ static cairo_surface_t *blur_surface(cairo_surface_t *surface, double x, cairo_surface_get_device_scale(surface, &scale_x, &scale_y); - g_debug("blurring surface at: %.2lf, %.2lf (%.2lfx%.2lf)", x, y, width, - height); - cairo_format_t src_format = cairo_image_surface_get_format(surface); switch (src_format) { case CAIRO_FORMAT_A1: @@ -52,13 +48,10 @@ static cairo_surface_t *blur_surface(cairo_surface_t *surface, double x, break; } - src = cairo_image_surface_get_data(surface); src_stride = cairo_image_surface_get_stride(surface); src_width = cairo_image_surface_get_width(surface); src_height = cairo_image_surface_get_height(surface); - g_debug("src surface (%dx%d)", src_width, src_height); - g_assert(src_height >= height); g_assert(src_width >= width); @@ -86,75 +79,74 @@ static cairo_surface_t *blur_surface(cairo_surface_t *surface, double x, tmp = cairo_image_surface_get_data(tmp_surface); dst_stride = cairo_image_surface_get_stride(dest_surface); + nb_passes = (guint)sqrt(scale_x * scale_y) + 1; + struct gaussian_kernel *gaussian = gaussian_kernel(4, 3.1); int start_x = CLAMP(x * scale_x, 0, src_width); - // int start_y = CLAMP(y - offset_y, 0, src_height; int start_y = CLAMP(y * scale_y, 0, src_height); int end_x = CLAMP((x + width) * scale_x, 0, src_width); - // int end_y = CLAMP(y + height + offset_y, 0, src_height); int end_y = CLAMP((y + height) * scale_y, 0, src_height); - g_debug("blurring happening from: %d, %d to: %d, %d", start_x, start_y, end_x, - end_y); - sum = (guint)gaussian->sum; - /* Horizontally blur from surface -> tmp */ - for (i = start_y; i < end_y; i++) { - s = (uint32_t *)(src + i * src_stride); - d = (uint32_t *)(tmp + i * dst_stride); - for (j = start_x; j < end_x; j++) { - u = v = w = z = 0; - for (k = 0; k < gaussian->size; k++) { - gdouble multiplier = gaussian->kernel[k]; - - if (j - half + k < 0 || j - half + k >= src_width) { - continue; + for (pass = 0; pass < nb_passes; pass++) { + /* Horizontally blur from surface -> tmp */ + for (i = start_y; i < end_y; i++) { + s = (uint32_t *)(dst + i * src_stride); + d = (uint32_t *)(tmp + i * dst_stride); + for (j = start_x; j < end_x; j++) { + u = v = w = z = 0; + for (k = 0; k < gaussian->size; k++) { + gdouble multiplier = gaussian->kernel[k]; + + if (j - half + k < 0 || j - half + k >= src_width) { + continue; + } + + p = s[j - half + k]; + + u += ((p >> 24) & 0xff) * multiplier; + v += ((p >> 16) & 0xff) * multiplier; + w += ((p >> 8) & 0xff) * multiplier; + z += ((p >> 0) & 0xff) * multiplier; } - p = s[j - half + k]; - - u += ((p >> 24) & 0xff) * multiplier; - v += ((p >> 16) & 0xff) * multiplier; - w += ((p >> 8) & 0xff) * multiplier; - z += ((p >> 0) & 0xff) * multiplier; + d[j] = (u / sum << 24) | (v / sum << 16) | (w / sum << 8) | z / sum; } - - d[j] = (u / sum << 24) | (v / sum << 16) | (w / sum << 8) | z / sum; } - } - - /* Then vertically blur from tmp -> surface */ - for (i = start_y; i < end_y; i++) { - d = (uint32_t *)(dst + i * dst_stride); - for (j = start_x; j < end_x; j++) { - u = v = w = z = 0; - for (k = 0; k < gaussian->size; k++) { - gdouble multiplier = gaussian->kernel[k]; - if (i - half + k < 0 || i - half + k >= src_height) { - continue; + /* Then vertically blur from tmp -> surface */ + for (i = start_y; i < end_y; i++) { + d = (uint32_t *)(dst + i * dst_stride); + for (j = start_x; j < end_x; j++) { + u = v = w = z = 0; + for (k = 0; k < gaussian->size; k++) { + gdouble multiplier = gaussian->kernel[k]; + + if (i - half + k < 0 || i - half + k >= src_height) { + continue; + } + + s = (uint32_t *)(tmp + (i - half + k) * dst_stride); + p = s[j]; + + u += ((p >> 24) & 0xff) * multiplier; + v += ((p >> 16) & 0xff) * multiplier; + w += ((p >> 8) & 0xff) * multiplier; + z += ((p >> 0) & 0xff) * multiplier; } - s = (uint32_t *)(tmp + (i - half + k) * dst_stride); - p = s[j]; - - u += ((p >> 24) & 0xff) * multiplier; - v += ((p >> 16) & 0xff) * multiplier; - w += ((p >> 8) & 0xff) * multiplier; - z += ((p >> 0) & 0xff) * multiplier; + d[j] = (u / sum << 24) | (v / sum << 16) | (w / sum << 8) | z / sum; } - - d[j] = (u / sum << 24) | (v / sum << 16) | (w / sum << 8) | z / sum; } } // Mark destination surface as dirty since it was altered with custom data. cairo_surface_mark_dirty(dest_surface); - cairo_surface_t *final = - cairo_image_surface_create(src_format, (int)(width * scale_x), (int)(height * scale_y)); + cairo_surface_t *final = cairo_image_surface_create( + src_format, (int)(width * scale_x), (int)(height * scale_y)); cairo_surface_set_device_scale(final, scale_x, scale_y); cr = cairo_create(final); cairo_set_source_surface(cr, dest_surface, -x, -y); @@ -371,8 +363,6 @@ static void render_blur(cairo_t *cr, struct swappy_paint *paint) { double a, b; cairo_surface_get_device_scale(target, &a, &b); - g_debug("cairo surface device scale: %.2lf, %.2lf", a, b); - double x = MIN(blur.from.x, blur.to.x); double y = MIN(blur.from.y, blur.to.y); double w = ABS(blur.from.x - blur.to.x);