mirror of
https://github.com/jtheoof/swappy.git
synced 2024-08-17 02:30:47 +03:00
fix(blur): use rendered surface after commit
- Fix blur logic - Reused rendered surface to optimize future render on comitted blur - Include gaussian kernel function Closes #20 Closes #22
This commit is contained in:
parent
416b0adad9
commit
46fb08dce1
13
include/algebra.h
Normal file
13
include/algebra.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
struct gaussian_kernel {
|
||||||
|
gdouble *kernel;
|
||||||
|
gint size;
|
||||||
|
gdouble sigma;
|
||||||
|
gdouble sum;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct gaussian_kernel *gaussian_kernel(gint width, gdouble sigma);
|
||||||
|
void gaussian_kernel_free(gpointer data);
|
@ -79,9 +79,10 @@ struct swappy_paint_brush {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct swappy_paint_blur {
|
struct swappy_paint_blur {
|
||||||
double bluriness;
|
double blur_level;
|
||||||
struct swappy_point from;
|
struct swappy_point from;
|
||||||
struct swappy_point to;
|
struct swappy_point to;
|
||||||
|
cairo_surface_t *surface;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct swappy_paint {
|
struct swappy_paint {
|
||||||
|
@ -5,3 +5,4 @@
|
|||||||
|
|
||||||
void string_remove_at(char *str, size_t pos);
|
void string_remove_at(char *str, size_t pos);
|
||||||
gchar *string_insert_chars_at(gchar *str, gchar *chars, size_t pos);
|
gchar *string_insert_chars_at(gchar *str, gchar *chars, size_t pos);
|
||||||
|
void pixel_data_print(guint32 pixel);
|
||||||
|
@ -51,6 +51,7 @@ executable(
|
|||||||
swappy_resources,
|
swappy_resources,
|
||||||
files([
|
files([
|
||||||
'src/main.c',
|
'src/main.c',
|
||||||
|
'src/algebra.c',
|
||||||
'src/application.c',
|
'src/application.c',
|
||||||
'src/buffer.c',
|
'src/buffer.c',
|
||||||
'src/box.c',
|
'src/box.c',
|
||||||
|
37
src/algebra.c
Normal file
37
src/algebra.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "algebra.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
struct gaussian_kernel *gaussian_kernel(int width, double sigma) {
|
||||||
|
double sum = 0;
|
||||||
|
gint size = width * width + 1;
|
||||||
|
double *kernel = g_new(double, size);
|
||||||
|
struct gaussian_kernel *gaussian = g_new(struct gaussian_kernel, 1);
|
||||||
|
for (gint y = 0; y < width; y++) {
|
||||||
|
for (gint x = 0; x < width; x++) {
|
||||||
|
double j = y - width;
|
||||||
|
double i = x - width;
|
||||||
|
double cell = ((1.0 / (2.0 * G_PI * sigma)) *
|
||||||
|
exp((-(i * i + j * j)) / (2.0 * sigma * sigma))) *
|
||||||
|
0xff;
|
||||||
|
kernel[y * width + x] = cell;
|
||||||
|
sum += cell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gaussian->kernel = kernel;
|
||||||
|
gaussian->size = size;
|
||||||
|
gaussian->sigma = sigma;
|
||||||
|
gaussian->sum = sum;
|
||||||
|
|
||||||
|
return gaussian;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gaussian_kernel_free(gpointer data) {
|
||||||
|
struct gaussian_kernel *gaussian = (struct gaussian_kernel *)data;
|
||||||
|
if (gaussian != NULL) {
|
||||||
|
g_free(gaussian->kernel);
|
||||||
|
g_free(gaussian);
|
||||||
|
}
|
||||||
|
}
|
@ -406,11 +406,18 @@ gboolean draw_area_configure_handler(GtkWidget *widget,
|
|||||||
g_debug("received configure_event handler");
|
g_debug("received configure_event handler");
|
||||||
cairo_surface_destroy(state->cairo_surface);
|
cairo_surface_destroy(state->cairo_surface);
|
||||||
|
|
||||||
state->cairo_surface = gdk_window_create_similar_surface(
|
cairo_surface_t *surface = gdk_window_create_similar_surface(
|
||||||
gtk_widget_get_window(widget), CAIRO_CONTENT_COLOR,
|
gtk_widget_get_window(widget), CAIRO_CONTENT_COLOR_ALPHA,
|
||||||
gtk_widget_get_allocated_width(widget),
|
gtk_widget_get_allocated_width(widget),
|
||||||
gtk_widget_get_allocated_height(widget));
|
gtk_widget_get_allocated_height(widget));
|
||||||
|
|
||||||
|
g_info("size of cairo_surface: %ux%u with type: %d",
|
||||||
|
cairo_image_surface_get_width(surface),
|
||||||
|
cairo_image_surface_get_height(surface),
|
||||||
|
cairo_image_surface_get_format(surface));
|
||||||
|
|
||||||
|
state->cairo_surface = surface;
|
||||||
|
|
||||||
render_state(state);
|
render_state(state);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
16
src/paint.c
16
src/paint.c
@ -23,6 +23,9 @@ void paint_free(gpointer data) {
|
|||||||
|
|
||||||
switch (paint->type) {
|
switch (paint->type) {
|
||||||
case SWAPPY_PAINT_MODE_BLUR:
|
case SWAPPY_PAINT_MODE_BLUR:
|
||||||
|
if (paint->content.blur.surface) {
|
||||||
|
cairo_surface_destroy(paint->content.blur.surface);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SWAPPY_PAINT_MODE_BRUSH:
|
case SWAPPY_PAINT_MODE_BRUSH:
|
||||||
g_list_free_full(paint->content.brush.points, g_free);
|
g_list_free_full(paint->content.brush.points, g_free);
|
||||||
@ -70,7 +73,7 @@ void paint_add_temporary(struct swappy_state *state, double x, double y,
|
|||||||
if (type == SWAPPY_PAINT_MODE_TEXT) {
|
if (type == SWAPPY_PAINT_MODE_TEXT) {
|
||||||
paint_commit_temporary(state);
|
paint_commit_temporary(state);
|
||||||
} else {
|
} else {
|
||||||
g_free(state->temp_paint);
|
paint_free(state->temp_paint);
|
||||||
state->temp_paint = NULL;
|
state->temp_paint = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,9 +82,10 @@ void paint_add_temporary(struct swappy_state *state, double x, double y,
|
|||||||
case SWAPPY_PAINT_MODE_BLUR:
|
case SWAPPY_PAINT_MODE_BLUR:
|
||||||
paint->can_draw = false;
|
paint->can_draw = false;
|
||||||
|
|
||||||
paint->content.blur.bluriness = state->settings.blur_level;
|
paint->content.blur.blur_level = state->settings.blur_level;
|
||||||
paint->content.blur.from.x = x;
|
paint->content.blur.from.x = x;
|
||||||
paint->content.blur.from.y = y;
|
paint->content.blur.from.y = y;
|
||||||
|
paint->content.blur.surface = NULL;
|
||||||
break;
|
break;
|
||||||
case SWAPPY_PAINT_MODE_BRUSH:
|
case SWAPPY_PAINT_MODE_BRUSH:
|
||||||
paint->can_draw = true;
|
paint->can_draw = true;
|
||||||
@ -147,6 +151,14 @@ void paint_update_temporary_shape(struct swappy_state *state, double x,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t width = state->window->width;
|
||||||
|
int32_t height = state->window->height;
|
||||||
|
|
||||||
|
// Bounding x and y to the window dimensions to avoid side effects in
|
||||||
|
// rendering.
|
||||||
|
x = fmin(fmax(x, 0), width);
|
||||||
|
y = fmin(fmax(y, 0), height);
|
||||||
|
|
||||||
switch (paint->type) {
|
switch (paint->type) {
|
||||||
case SWAPPY_PAINT_MODE_BLUR:
|
case SWAPPY_PAINT_MODE_BLUR:
|
||||||
paint->can_draw = true;
|
paint->can_draw = true;
|
||||||
|
249
src/render.c
249
src/render.c
@ -1,157 +1,152 @@
|
|||||||
#include <gdk/gdk.h>
|
#include <glib.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <pango/pangocairo.h>
|
#include <pango/pangocairo.h>
|
||||||
|
|
||||||
|
#include "algebra.h"
|
||||||
#include "swappy.h"
|
#include "swappy.h"
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#ifndef M_PI
|
|
||||||
#define M_PI (3.14159265358979323846)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define RENDER_PANGO_FONT SWAPPY_TEXT_FONT_DEFAULT SWAPPY_TEXT_SIZE_DEFAULT
|
|
||||||
|
|
||||||
#define pango_layout_t PangoLayout
|
#define pango_layout_t PangoLayout
|
||||||
#define pango_font_description_t PangoFontDescription
|
#define pango_font_description_t PangoFontDescription
|
||||||
#define pango_rectangle_t PangoRectangle
|
#define pango_rectangle_t PangoRectangle
|
||||||
|
|
||||||
#define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a)[0])
|
|
||||||
|
|
||||||
static struct swappy_point swappy_point_scaled(struct swappy_point point,
|
|
||||||
gint scale) {
|
|
||||||
struct swappy_point ret = {
|
|
||||||
.x = point.x * scale,
|
|
||||||
.y = point.y * scale,
|
|
||||||
};
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This code was largely taken from Kristian Høgsberg and Chris Wilson from:
|
* This code was largely taken from Kristian Høgsberg and Chris Wilson from:
|
||||||
* https://www.cairographics.org/cookbook/blur.c/
|
* https://www.cairographics.org/cookbook/blur.c/
|
||||||
*/
|
*/
|
||||||
static void blur_paint(cairo_t *cr, struct swappy_paint_blur *blur,
|
static cairo_surface_t *blur_surface(cairo_surface_t *surface, double x,
|
||||||
gint scaling_factor) {
|
double y, double width, double height,
|
||||||
cairo_surface_t *tmp;
|
gint blur_level) {
|
||||||
int width, height;
|
cairo_surface_t *dest_surface, *tmp_surface;
|
||||||
|
cairo_t *cr;
|
||||||
|
int src_width, src_height;
|
||||||
int src_stride, dst_stride;
|
int src_stride, dst_stride;
|
||||||
int x, y, z, w;
|
guint u, v, w, z;
|
||||||
uint8_t *src, *dst;
|
uint8_t *src, *dst, *tmp;
|
||||||
uint32_t *s, *d, a, p;
|
uint32_t *s, *d, p;
|
||||||
int i, j, k;
|
int i, j, k;
|
||||||
uint8_t kernel[17];
|
const int size = (int)blur_level * 2 + 1;
|
||||||
const int size = ARRAY_LENGTH(kernel);
|
|
||||||
const int half = size / 2;
|
const int half = size / 2;
|
||||||
double bluriness = blur->bluriness;
|
const double offset_y = 10.0;
|
||||||
struct swappy_point from = swappy_point_scaled(blur->from, scaling_factor);
|
guint sum;
|
||||||
struct swappy_point to = swappy_point_scaled(blur->to, scaling_factor);
|
|
||||||
|
|
||||||
cairo_surface_t *surface = cairo_get_target(cr);
|
if (cairo_surface_status(surface)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (cairo_surface_status(surface)) return;
|
cairo_format_t src_format = cairo_image_surface_get_format(surface);
|
||||||
|
switch (src_format) {
|
||||||
width = cairo_image_surface_get_width(surface);
|
|
||||||
height = cairo_image_surface_get_height(surface);
|
|
||||||
|
|
||||||
switch (cairo_image_surface_get_format(surface)) {
|
|
||||||
case CAIRO_FORMAT_A1:
|
case CAIRO_FORMAT_A1:
|
||||||
default:
|
|
||||||
/* Don't even think about it! */
|
|
||||||
return;
|
|
||||||
|
|
||||||
case CAIRO_FORMAT_A8:
|
case CAIRO_FORMAT_A8:
|
||||||
/* Handle a8 surfaces by effectively unrolling the loops by a
|
|
||||||
* factor of 4 - this is safe since we know that stride has to be a
|
|
||||||
* multiple of uint32_t. */
|
|
||||||
width /= 4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CAIRO_FORMAT_RGB24:
|
case CAIRO_FORMAT_RGB24:
|
||||||
|
default:
|
||||||
|
g_warning("source surface format: %d is not supported", src_format);
|
||||||
|
return NULL;
|
||||||
case CAIRO_FORMAT_ARGB32:
|
case CAIRO_FORMAT_ARGB32:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
|
||||||
if (cairo_surface_status(tmp)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
src = cairo_image_surface_get_data(surface);
|
src = cairo_image_surface_get_data(surface);
|
||||||
src_stride = cairo_image_surface_get_stride(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("sizeof(src): %lu", sizeof(src));
|
g_assert(src_height >= height);
|
||||||
g_debug("width*height*stride: %d", width * height * src_stride);
|
g_assert(src_width >= width);
|
||||||
|
|
||||||
dst = cairo_image_surface_get_data(tmp);
|
dest_surface = cairo_image_surface_create(src_format, src_width, src_height);
|
||||||
dst_stride = cairo_image_surface_get_stride(tmp);
|
tmp_surface = cairo_image_surface_create(src_format, src_width, src_height);
|
||||||
|
|
||||||
a = 0;
|
if (cairo_surface_status(dest_surface) || cairo_surface_status(tmp_surface)) {
|
||||||
for (i = 0; i < size; i++) {
|
return NULL;
|
||||||
double f = i - half;
|
|
||||||
a += kernel[i] = exp(-f * f / bluriness) * 80;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int start_x = fmax(fmin(from.x, to.x), 0);
|
cr = cairo_create(tmp_surface);
|
||||||
int start_y = fmax(fmin(from.y, to.y), 0);
|
cairo_set_source_surface(cr, surface, 0, 0);
|
||||||
|
cairo_paint(cr);
|
||||||
|
cairo_destroy(cr);
|
||||||
|
|
||||||
int max_x = fmin(fmax(from.x, to.x), width);
|
cr = cairo_create(dest_surface);
|
||||||
int max_y = fmin(fmax(from.y, to.y), height);
|
cairo_set_source_surface(cr, surface, 0, 0);
|
||||||
|
cairo_paint(cr);
|
||||||
|
cairo_destroy(cr);
|
||||||
|
|
||||||
for (i = 0; i < height; i++) {
|
dst = cairo_image_surface_get_data(dest_surface);
|
||||||
s = (uint32_t *)(src + i * src_stride);
|
tmp = cairo_image_surface_get_data(tmp_surface);
|
||||||
d = (uint32_t *)(dst + i * dst_stride);
|
dst_stride = cairo_image_surface_get_stride(dest_surface);
|
||||||
for (j = 0; j < width; j++) {
|
|
||||||
d[j] = s[j];
|
struct gaussian_kernel *gaussian = gaussian_kernel(4, 3.1);
|
||||||
}
|
|
||||||
}
|
int start_x = CLAMP(x, 0, src_width);
|
||||||
|
int start_y = CLAMP(y - offset_y, 0, src_height);
|
||||||
|
|
||||||
|
int end_x = CLAMP(x + width, 0, src_width);
|
||||||
|
int end_y = CLAMP(y + height + offset_y, 0, src_height);
|
||||||
|
|
||||||
|
sum = (guint)gaussian->sum;
|
||||||
|
|
||||||
/* Horizontally blur from surface -> tmp */
|
/* Horizontally blur from surface -> tmp */
|
||||||
for (i = start_y; i < max_y; i++) {
|
for (i = start_y; i < end_y; i++) {
|
||||||
s = (uint32_t *)(src + i * src_stride);
|
s = (uint32_t *)(src + i * src_stride);
|
||||||
d = (uint32_t *)(dst + i * dst_stride);
|
d = (uint32_t *)(tmp + i * dst_stride);
|
||||||
for (j = start_x; j < max_x; j++) {
|
for (j = start_x; j < end_x; j++) {
|
||||||
x = y = z = w = 0;
|
u = v = w = z = 0;
|
||||||
for (k = 0; k < size; k++) {
|
for (k = 0; k < gaussian->size; k++) {
|
||||||
if (j - half + k < 0 || j - half + k >= width) continue;
|
gdouble multiplier = gaussian->kernel[k];
|
||||||
|
|
||||||
|
if (j - half + k < 0 || j - half + k >= src_width) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
p = s[j - half + k];
|
p = s[j - half + k];
|
||||||
|
|
||||||
x += ((p >> 24) & 0xff) * kernel[k];
|
u += ((p >> 24) & 0xff) * multiplier;
|
||||||
y += ((p >> 16) & 0xff) * kernel[k];
|
v += ((p >> 16) & 0xff) * multiplier;
|
||||||
z += ((p >> 8) & 0xff) * kernel[k];
|
w += ((p >> 8) & 0xff) * multiplier;
|
||||||
w += ((p >> 0) & 0xff) * kernel[k];
|
z += ((p >> 0) & 0xff) * multiplier;
|
||||||
}
|
}
|
||||||
d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
|
|
||||||
|
d[j] = (u / sum << 24) | (v / sum << 16) | (w / sum << 8) | z / sum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Then vertically blur from tmp -> surface */
|
/* Then vertically blur from tmp -> surface */
|
||||||
for (i = start_y; i < max_y; i++) {
|
for (i = start_y; i < end_y; i++) {
|
||||||
s = (uint32_t *)(dst + i * dst_stride);
|
d = (uint32_t *)(dst + i * dst_stride);
|
||||||
d = (uint32_t *)(src + i * src_stride);
|
for (j = start_x; j < end_x; j++) {
|
||||||
for (j = start_x; j < max_x; j++) {
|
u = v = w = z = 0;
|
||||||
x = y = z = w = 0;
|
for (k = 0; k < gaussian->size; k++) {
|
||||||
for (k = 0; k < size; k++) {
|
gdouble multiplier = gaussian->kernel[k];
|
||||||
if (i - half + k < 0 || i - half + k >= height) {
|
|
||||||
|
if (i - half + k < 0 || i - half + k >= src_height) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = (uint32_t *)(dst + (i - half + k) * dst_stride);
|
s = (uint32_t *)(tmp + (i - half + k) * dst_stride);
|
||||||
p = s[j];
|
p = s[j];
|
||||||
|
|
||||||
x += ((p >> 24) & 0xff) * kernel[k];
|
u += ((p >> 24) & 0xff) * multiplier;
|
||||||
y += ((p >> 16) & 0xff) * kernel[k];
|
v += ((p >> 16) & 0xff) * multiplier;
|
||||||
z += ((p >> 8) & 0xff) * kernel[k];
|
w += ((p >> 8) & 0xff) * multiplier;
|
||||||
w += ((p >> 0) & 0xff) * kernel[k];
|
z += ((p >> 0) & 0xff) * multiplier;
|
||||||
}
|
}
|
||||||
d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
|
|
||||||
|
d[j] = (u / sum << 24) | (v / sum << 16) | (w / sum << 8) | z / sum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_surface_destroy(tmp);
|
// Mark destination surface as dirty since it was altered with custom data.
|
||||||
cairo_surface_mark_dirty(surface);
|
cairo_surface_mark_dirty(dest_surface);
|
||||||
|
cairo_surface_t *final =
|
||||||
|
cairo_image_surface_create(src_format, (int)width, (int)height);
|
||||||
|
cr = cairo_create(final);
|
||||||
|
cairo_set_source_surface(cr, dest_surface, -x, -y);
|
||||||
|
cairo_paint(cr);
|
||||||
|
cairo_destroy(cr);
|
||||||
|
cairo_surface_destroy(dest_surface);
|
||||||
|
cairo_surface_destroy(tmp_surface);
|
||||||
|
gaussian_kernel_free(gaussian);
|
||||||
|
return final;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void convert_pango_rectangle_to_swappy_box(pango_rectangle_t rectangle,
|
static void convert_pango_rectangle_to_swappy_box(pango_rectangle_t rectangle,
|
||||||
@ -227,7 +222,7 @@ static void render_shape_arrow(cairo_t *cr, struct swappy_paint_shape shape) {
|
|||||||
double r = 20;
|
double r = 20;
|
||||||
double scaling_factor = shape.w / 4;
|
double scaling_factor = shape.w / 4;
|
||||||
|
|
||||||
double alpha = M_PI / 6;
|
double alpha = G_PI / 6;
|
||||||
double ta = 5 * alpha;
|
double ta = 5 * alpha;
|
||||||
double tb = 7 * alpha;
|
double tb = 7 * alpha;
|
||||||
double xa = r * cos(ta);
|
double xa = r * cos(ta);
|
||||||
@ -284,7 +279,7 @@ static void render_shape_ellipse(cairo_t *cr, struct swappy_paint_shape shape) {
|
|||||||
cairo_get_matrix(cr, &save_matrix);
|
cairo_get_matrix(cr, &save_matrix);
|
||||||
cairo_translate(cr, xc, yc);
|
cairo_translate(cr, xc, yc);
|
||||||
cairo_scale(cr, x / n, y / n);
|
cairo_scale(cr, x / n, y / n);
|
||||||
cairo_arc(cr, 0, 0, r, 0, 2 * M_PI);
|
cairo_arc(cr, 0, 0, r, 0, 2 * G_PI);
|
||||||
cairo_set_matrix(cr, &save_matrix);
|
cairo_set_matrix(cr, &save_matrix);
|
||||||
cairo_stroke(cr);
|
cairo_stroke(cr);
|
||||||
cairo_close_path(cr);
|
cairo_close_path(cr);
|
||||||
@ -344,14 +339,37 @@ static void render_buffers(cairo_t *cr, struct swappy_state *state) {
|
|||||||
cairo_restore(cr);
|
cairo_restore(cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void render_background(cairo_t *cr) {
|
static void render_background(cairo_t *cr, struct swappy_state *state) {
|
||||||
cairo_set_source_rgb(cr, 0, 0, 0);
|
cairo_set_source_rgb(cr, 0, 0, 0);
|
||||||
cairo_paint(cr);
|
cairo_paint(cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void render_blur(cairo_t *cr, struct swappy_paint_blur blur,
|
static void render_blur(cairo_t *cr, struct swappy_paint *paint,
|
||||||
bool is_committed, gint scaling_factor) {
|
gint scaling_factor) {
|
||||||
if (!is_committed) {
|
struct swappy_paint_blur blur = paint->content.blur;
|
||||||
|
|
||||||
|
cairo_surface_t *target = cairo_get_target(cr);
|
||||||
|
|
||||||
|
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);
|
||||||
|
double h = ABS(blur.from.y - blur.to.y);
|
||||||
|
|
||||||
|
cairo_save(cr);
|
||||||
|
|
||||||
|
if (!paint->is_committed) {
|
||||||
|
cairo_surface_t *blurred =
|
||||||
|
blur_surface(target, x, y, w, h, blur.blur_level);
|
||||||
|
|
||||||
|
if (blurred && cairo_surface_status(blurred) == CAIRO_STATUS_SUCCESS) {
|
||||||
|
cairo_set_source_surface(cr, blurred, x, y);
|
||||||
|
cairo_paint(cr);
|
||||||
|
if (blur.surface) {
|
||||||
|
cairo_surface_destroy(blur.surface);
|
||||||
|
}
|
||||||
|
paint->content.blur.surface = blurred;
|
||||||
|
}
|
||||||
|
|
||||||
// Blur not committed yet, draw bounding rectangle
|
// Blur not committed yet, draw bounding rectangle
|
||||||
struct swappy_paint_shape rect = {
|
struct swappy_paint_shape rect = {
|
||||||
.r = 0,
|
.r = 0,
|
||||||
@ -364,8 +382,16 @@ static void render_blur(cairo_t *cr, struct swappy_paint_blur blur,
|
|||||||
.type = SWAPPY_PAINT_MODE_RECTANGLE,
|
.type = SWAPPY_PAINT_MODE_RECTANGLE,
|
||||||
};
|
};
|
||||||
render_shape_rectangle(cr, rect);
|
render_shape_rectangle(cr, rect);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cairo_surface_t *surface = blur.surface;
|
||||||
|
if (surface && cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS) {
|
||||||
|
cairo_set_source_surface(cr, surface, x, y);
|
||||||
|
cairo_paint(cr);
|
||||||
}
|
}
|
||||||
blur_paint(cr, &blur, scaling_factor);
|
}
|
||||||
|
|
||||||
|
cairo_restore(cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void render_brush(cairo_t *cr, struct swappy_paint_brush brush) {
|
static void render_brush(cairo_t *cr, struct swappy_paint_brush brush) {
|
||||||
@ -395,7 +421,7 @@ static void render_paint(cairo_t *cr, struct swappy_paint *paint,
|
|||||||
}
|
}
|
||||||
switch (paint->type) {
|
switch (paint->type) {
|
||||||
case SWAPPY_PAINT_MODE_BLUR:
|
case SWAPPY_PAINT_MODE_BLUR:
|
||||||
render_blur(cr, paint->content.blur, paint->is_committed, scaling_factor);
|
render_blur(cr, paint, scaling_factor);
|
||||||
break;
|
break;
|
||||||
case SWAPPY_PAINT_MODE_BRUSH:
|
case SWAPPY_PAINT_MODE_BRUSH:
|
||||||
render_brush(cr, paint->content.brush);
|
render_brush(cr, paint->content.brush);
|
||||||
@ -426,14 +452,15 @@ static void render_paints(cairo_t *cr, struct swappy_state *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void render_state(struct swappy_state *state) {
|
void render_state(struct swappy_state *state) {
|
||||||
cairo_t *cr = cairo_create(state->cairo_surface);
|
cairo_surface_t *surface = state->cairo_surface;
|
||||||
|
cairo_t *cr = cairo_create(surface);
|
||||||
|
|
||||||
render_background(cr);
|
render_background(cr, state);
|
||||||
render_buffers(cr, state);
|
render_buffers(cr, state);
|
||||||
render_paints(cr, state);
|
render_paints(cr, state);
|
||||||
|
|
||||||
|
cairo_destroy(cr);
|
||||||
|
|
||||||
// Drawing is finished, notify the GtkDrawingArea it needs to be redrawn.
|
// Drawing is finished, notify the GtkDrawingArea it needs to be redrawn.
|
||||||
gtk_widget_queue_draw(state->ui->area);
|
gtk_widget_queue_draw(state->ui->area);
|
||||||
|
|
||||||
cairo_destroy(cr);
|
|
||||||
}
|
}
|
||||||
|
10
src/util.c
10
src/util.c
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
@ -37,3 +36,12 @@ gchar *string_insert_chars_at(gchar *str, gchar *chars, size_t pos) {
|
|||||||
|
|
||||||
return new_str;
|
return new_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pixel_data_print(guint32 pixel) {
|
||||||
|
const guint32 r = pixel >> 24 & 0xff;
|
||||||
|
const guint32 g = pixel >> 16 & 0xff;
|
||||||
|
const guint32 b = pixel >> 8 & 0xff;
|
||||||
|
const guint32 a = pixel >> 0 & 0xff;
|
||||||
|
|
||||||
|
g_debug("rgba(%u, %d, %u, %u)", r, g, b, a);
|
||||||
|
}
|
||||||
|
BIN
test/images/passwords.png
Normal file
BIN
test/images/passwords.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.7 KiB |
Loading…
Reference in New Issue
Block a user