Rectangle kernels

Replace conv::size with conv::{w,h}.

Shadow kernels are still squares, though.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2019-02-17 21:54:35 +00:00
parent cea010afec
commit b2750b26e0
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
4 changed files with 32 additions and 32 deletions

View File

@ -71,7 +71,9 @@ xcb_image_t *make_shadow(xcb_connection_t *c, const conv *kernel,
*/ */
xcb_image_t *ximage; xcb_image_t *ximage;
const double *shadow_sum = kernel->rsum; 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; int swidth = width + r * 2, sheight = height + r * 2;
assert(d % 2 == 1); assert(d % 2 == 1);

View File

@ -12,32 +12,30 @@
/// top left corner is at (x, y) /// top left corner is at (x, y)
double sum_kernel(const conv *map, int x, int y, int width, int height) { double sum_kernel(const conv *map, int x, int y, int width, int height) {
double ret = 0; double ret = 0;
/*
* Compute set of filter values which are "in range"
*/
int xstart = x; // Compute sum of values which are "in range"
if (xstart < 0) int xstart = x, xend = width + x;
if (xstart < 0) {
xstart = 0; xstart = 0;
int xend = width + x; }
if (xend > map->size) if (xend > map->w) {
xend = map->size; xend = map->w;
}
int ystart = y; int ystart = y, yend = height + y;
if (ystart < 0) if (ystart < 0) {
ystart = 0; ystart = 0;
int yend = height + y; }
if (yend > map->size) if (yend > map->h) {
yend = map->size; yend = map->h;
}
assert(yend >= ystart && xend >= xstart);
assert(yend > 0 && xend > 0); int d = map->w;
int d = map->size;
if (map->rsum) { if (map->rsum) {
// See sum_kernel_preprocess
double v1 = xstart ? map->rsum[(yend - 1) * d + xstart - 1] : 0; double v1 = xstart ? map->rsum[(yend - 1) * d + xstart - 1] : 0;
double v2 = ystart ? map->rsum[(ystart - 1) * d + xend - 1] : 0; double v2 = ystart ? map->rsum[(ystart - 1) * d + xend - 1] : 0;
double v3 = double v3 = (xstart && ystart) ? map->rsum[(ystart - 1) * d + xstart - 1] : 0;
(xstart && ystart) ? map->rsum[(ystart - 1) * d + xstart - 1] : 0;
return map->rsum[(yend - 1) * d + xend - 1] - v1 - v2 + v3; return map->rsum[(yend - 1) * d + xend - 1] - v1 - v2 + v3;
} }
@ -77,7 +75,7 @@ conv *gaussian_kernel(double r) {
double t; double t;
c = cvalloc(sizeof(conv) + size * size * sizeof(double)); c = cvalloc(sizeof(conv) + size * size * sizeof(double));
c->size = size; c->w = c->h = size;
c->rsum = NULL; c->rsum = NULL;
t = 0.0; t = 0.0;
@ -100,22 +98,22 @@ conv *gaussian_kernel(double r) {
/// preprocess kernels to make shadow generation faster /// 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 /// 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) {
const int d = map->size; if (map->rsum) {
if (map->rsum)
free(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]; 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]; 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]; 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] - double tmp = sum[(y - 1) * d + x] + sum[y * d + x - 1] -
sum[(y - 1) * d + x - 1]; sum[(y - 1) * d + x - 1];
sum[y * d + x] = tmp + map->data[y * d + x]; sum[y * d + x] = tmp + map->data[y * d + x];

View File

@ -8,7 +8,7 @@
/// Code for generating convolution kernels /// Code for generating convolution kernels
typedef struct conv { typedef struct conv {
int size; int w, h;
double *rsum; double *rsum;
double data[]; double data[];
} conv; } conv;
@ -23,7 +23,7 @@ conv *gaussian_kernel(double r);
/// preprocess kernels to make shadow generation faster /// 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 /// 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) { static inline void free_conv(conv *k) {
free(k->rsum); free(k->rsum);

View File

@ -1169,7 +1169,7 @@ bool init_render(session_t *ps) {
} }
ps->gaussian_map = gaussian_kernel(ps->o.shadow_radius); 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->black_picture = solid_picture(ps, true, 1, 0, 0, 0);
ps->white_picture = solid_picture(ps, true, 1, 1, 1, 1); ps->white_picture = solid_picture(ps, true, 1, 1, 1, 1);