diff --git a/src/backend/backend_common.c b/src/backend/backend_common.c index c6a1690..632fe2a 100644 --- a/src/backend/backend_common.c +++ b/src/backend/backend_common.c @@ -71,7 +71,9 @@ xcb_image_t *make_shadow(xcb_connection_t *c, const conv *kernel, */ xcb_image_t *ximage; const double *shadow_sum = kernel->rsum; - int d = kernel->size, r = d / 2; + // We only support square kernels for shadow + assert(kernel->w == kernel->h); + int d = kernel->w, r = d / 2; int swidth = width + r * 2, sheight = height + r * 2; assert(d % 2 == 1); diff --git a/src/kernel.c b/src/kernel.c index 86eb4af..07d810c 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -12,32 +12,30 @@ /// top left corner is at (x, y) double sum_kernel(const conv *map, int x, int y, int width, int height) { double ret = 0; - /* - * Compute set of filter values which are "in range" - */ - int xstart = x; - if (xstart < 0) + // Compute sum of values which are "in range" + int xstart = x, xend = width + x; + if (xstart < 0) { xstart = 0; - int xend = width + x; - if (xend > map->size) - xend = map->size; - - int ystart = y; - if (ystart < 0) + } + if (xend > map->w) { + xend = map->w; + } + int ystart = y, yend = height + y; + if (ystart < 0) { ystart = 0; - int yend = height + y; - if (yend > map->size) - yend = map->size; + } + if (yend > map->h) { + yend = map->h; + } + assert(yend >= ystart && xend >= xstart); - assert(yend > 0 && xend > 0); - - int d = map->size; + int d = map->w; if (map->rsum) { + // See sum_kernel_preprocess double v1 = xstart ? map->rsum[(yend - 1) * d + xstart - 1] : 0; double v2 = ystart ? map->rsum[(ystart - 1) * d + xend - 1] : 0; - double v3 = - (xstart && ystart) ? map->rsum[(ystart - 1) * d + xstart - 1] : 0; + double v3 = (xstart && ystart) ? map->rsum[(ystart - 1) * d + xstart - 1] : 0; return map->rsum[(yend - 1) * d + xend - 1] - v1 - v2 + v3; } @@ -77,7 +75,7 @@ conv *gaussian_kernel(double r) { double t; c = cvalloc(sizeof(conv) + size * size * sizeof(double)); - c->size = size; + c->w = c->h = size; c->rsum = NULL; t = 0.0; @@ -100,22 +98,22 @@ conv *gaussian_kernel(double r) { /// preprocess kernels to make shadow generation faster /// shadow_sum[x*d+y] is the sum of the kernel from (0, 0) to (x, y), inclusive -void shadow_preprocess(conv *map) { - const int d = map->size; - - if (map->rsum) +void sum_kernel_preprocess(conv *map) { + if (map->rsum) { free(map->rsum); + } - auto sum = map->rsum = ccalloc(d * d, double); + auto sum = map->rsum = ccalloc(map->w * map->h, double); sum[0] = map->data[0]; - for (int x = 1; x < d; x++) { + for (int x = 1; x < map->w; x++) { sum[x] = sum[x - 1] + map->data[x]; } - for (int y = 1; y < d; y++) { + const int d = map->w; + for (int y = 1; y < map->h; y++) { sum[y * d] = sum[(y - 1) * d] + map->data[y * d]; - for (int x = 1; x < d; x++) { + for (int x = 1; x < map->w; x++) { double tmp = sum[(y - 1) * d + x] + sum[y * d + x - 1] - sum[(y - 1) * d + x - 1]; sum[y * d + x] = tmp + map->data[y * d + x]; diff --git a/src/kernel.h b/src/kernel.h index fdb6076..daf60d6 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -8,7 +8,7 @@ /// Code for generating convolution kernels typedef struct conv { - int size; + int w, h; double *rsum; double data[]; } conv; @@ -23,7 +23,7 @@ conv *gaussian_kernel(double r); /// preprocess kernels to make shadow generation faster /// shadow_sum[x*d+y] is the sum of the kernel from (0, 0) to (x, y), inclusive -void shadow_preprocess(conv *map); +void sum_kernel_preprocess(conv *map); static inline void free_conv(conv *k) { free(k->rsum); diff --git a/src/render.c b/src/render.c index 00c33e7..edf440b 100644 --- a/src/render.c +++ b/src/render.c @@ -1169,7 +1169,7 @@ bool init_render(session_t *ps) { } ps->gaussian_map = gaussian_kernel(ps->o.shadow_radius); - shadow_preprocess(ps->gaussian_map); + sum_kernel_preprocess(ps->gaussian_map); ps->black_picture = solid_picture(ps, true, 1, 0, 0, 0); ps->white_picture = solid_picture(ps, true, 1, 1, 1, 1);