Blur an Agar Surface

From Agar

Jump to: navigation, search

This routine blurs an Agar. AG_Surface(3). OpenGL users will probably use lenses or other features to accomplish this. Error-checking code is omitted.

This routine was ported from Java and is for blurring images using the frame buffer. It's optimized well with the input of several programmers. It was ported from Processing/Java. The original is by Mario Klingemann.

/*
 * CCA 2.5 - H.Elwood Gilliland III
 * Original gifted by Mario Klingemann
 * Make sure surface is unlocked
 * Modifies data in img and returns img
 * radius:number of pixels
 */
 
#define RED(pixel,fmt)         (((pixel&fmt->Rmask)>>fmt->Rshift)<<fmt->Rloss)
#define GREEN(pixel,fmt)       (((pixel&fmt->Gmask)>>fmt->Gshift)<<fmt->Gloss)
#define BLUE(pixel,fmt)        (((pixel&fmt->Bmask)>>fmt->Bshift)<<fmt->Bloss)
 
AG_Surface *
fastBlur(AG_Surface *img, int radius)
{
        int w, h, wm, hm, wh, dvd, worh;
        int rsum, gsum, bsum, x, y, i, p, p1, p2, yp, yi, yw;
        int *r, *g, *b, *vmax, *vmin, *dv;
        long rsize, gsize, bsize, vminsize, vmaxsize, dvsize;
 
        if (radius < 1) {
                return (img);
        }
        w = img->w;
        h = img->h;
        wm = w - 1;
        hm = h - 1;
        wh = w*h;
        dvd = radius + radius + 1;
 
        rsize = gsize = bsize = sizeof(int) * wh;
        vminsize = vmaxsize = sizeof(int) * (worh = UMAX(w,h));
        dvsize = 256*dvd;
        r = malloc(rsize);
        g = malloc(gsize);
        b = malloc(bsize);
        vmin = malloc(vminsize);
        vmax = malloc(vmaxsize);
        dv = malloc(sizeof(int)*dvsize);
 
        for (i = 0; i < dvsize; i++) {
                dv[i] = i / dvd;
        }
 
        yw = yi = 0;
 
        for (y = 0; y < h; y++) {
                rsum = gsum = bsum = 0;
                for (i = -radius; i <= radius; i++) {
                        p = AG_GET_PIXEL2(img, yi + UMIN(wm, UMAX(0, i)));
                        rsum += RED(p, img->format);
                        gsum += GREEN(p, img->format);
                        bsum += BLUE(p, img->format);
 
                }
                for (x = 0; x < w; x++) {
 
                        r[yi] = dv[rsum];
                        g[yi] = dv[gsum];
                        b[yi] = dv[bsum];
 
                        if (y == 0) {
                                vmin[x] = UMIN(x + radius + 1, wm);
                                vmax[x] = UMAX(0, x - radius);
                        }
                        p1 = AG_GET_PIXEL2(img, yw + vmin[x]);
                        p2 = AG_GET_PIXEL2(img, yw + vmax[x]);
 
                        rsum += RED(p1, img->format) - RED(p2, img->format);
                        gsum += GREEN(p1, img->format) - GREEN(p2, img->format);
                        bsum += BLUE(p1, img->format) - BLUE(p2, img->format);
                        yi++;
                }
                yw += w;
        }
 
        for (x = 0; x < w; x++) {
                rsum = gsum = bsum = 0;
                yp = -radius * w;
                for (i = -radius; i <= radius; i++) {
                        yi = UMAX(0, yp) + x;
                        rsum += r[yi];
                        gsum += g[yi];
                        bsum += b[yi];
                        yp += w;
                }
                yi = x;
                for (y = 0; y < h; y++) {
                        putpixel(img, x, y, COLOR(dv[rsum], dv[gsum], dv[bsum], 255, img->format));
                        if (x == 0) {
                                vmin[y] = UMIN(y + radius + 1, hm) * w;
                                vmax[y] = UMAX(y - radius, 0) * w;
                        }
                        p1 = x + vmin[y];
                        p2 = x + vmax[y];
 
                        rsum += r[p1] - r[p2];
                        gsum += g[p1] - g[p2];
                        bsum += b[p1] - b[p2];
                        yi += w;
                }
        }
 
        free(r);
        free(g);
        free(b);
        free(vmin);
        free(vmax);
        free(dv);
        return (img);
}
Personal tools