Пример #1
0
/* update the brush image by trying to reuse the cached texture result. this
 * can be considerably faster for brushes that change size due to pressure or
 * textures that stick to the surface where only part of the pixels are new */
static void brush_painter_imbuf_partial_update(BrushPainter *painter, const float pos[2])
{
    const Scene *scene = painter->scene;
    Brush *brush = painter->brush;
    BrushPainterCache *cache = &painter->cache;
    ImBuf *oldtexibuf, *ibuf;
    int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
    int diameter = 2 * BKE_brush_size_get(scene, brush);

    /* create brush image buffer if it didn't exist yet */
    imbflag = (cache->use_float) ? IB_rectfloat : IB_rect;
    if (!cache->ibuf)
        cache->ibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);
    ibuf = cache->ibuf;

    /* create new texture image buffer with coordinates relative to old */
    oldtexibuf = cache->texibuf;
    cache->texibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);

    if (oldtexibuf) {
        srcx = srcy = 0;
        destx = (int)painter->lastpaintpos[0] - (int)pos[0];
        desty = (int)painter->lastpaintpos[1] - (int)pos[1];
        w = oldtexibuf->x;
        h = oldtexibuf->y;

        IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
    }
    else {
        srcx = srcy = 0;
        destx = desty = 0;
        w = h = 0;
    }

    x1 = destx;
    y1 = desty;
    x2 = min_ii(destx + w, ibuf->x);
    y2 = min_ii(desty + h, ibuf->y);

    /* blend existing texture in new position */
    if ((x1 < x2) && (y1 < y2))
        brush_painter_imbuf_update(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy);

    if (oldtexibuf)
        IMB_freeImBuf(oldtexibuf);

    /* sample texture in new areas */
    if ((0 < x1) && (0 < ibuf->y))
        brush_painter_imbuf_update(painter, NULL, 0, 0, x1, ibuf->y, 0, 0);
    if ((x2 < ibuf->x) && (0 < ibuf->y))
        brush_painter_imbuf_update(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0);
    if ((x1 < x2) && (0 < y1))
        brush_painter_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0);
    if ((x1 < x2) && (y2 < ibuf->y))
        brush_painter_imbuf_update(painter, NULL, x1, y2, x2, ibuf->y, 0, 0);
}
Пример #2
0
static void brush_painter_fixed_tex_partial_update(BrushPainter *painter, const float pos[2])
{
	const Scene *scene = painter->scene;
	Brush *brush = painter->brush;
	BrushPainterCache *cache = &painter->cache;
	ImBuf *oldtexibuf, *ibuf;
	int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
	const int diameter = 2 * BKE_brush_size_get(scene, brush);

	imbflag = (cache->flt) ? IB_rectfloat : IB_rect;
	if (!cache->ibuf)
		cache->ibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);
	ibuf = cache->ibuf;

	oldtexibuf = cache->texibuf;
	cache->texibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);

	if (oldtexibuf) {
		srcx = srcy = 0;
		destx = (int)painter->lastpaintpos[0] - (int)pos[0];
		desty = (int)painter->lastpaintpos[1] - (int)pos[1];
		w = oldtexibuf->x;
		h = oldtexibuf->y;

		IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
	}
	else {
		srcx = srcy = 0;
		destx = desty = 0;
		w = h = 0;
	}
	
	x1 = destx;
	y1 = desty;
	x2 = destx + w;
	y2 = desty + h;

	/* blend existing texture in new position */
	if ((x1 < x2) && (y1 < y2))
		brush_painter_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos);

	if (oldtexibuf)
		IMB_freeImBuf(oldtexibuf);

	/* sample texture in new areas */
	if ((0 < x1) && (0 < ibuf->y))
		brush_painter_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos);
	if ((x2 < ibuf->x) && (0 < ibuf->y))
		brush_painter_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos);
	if ((x1 < x2) && (0 < y1))
		brush_painter_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos);
	if ((x1 < x2) && (y2 < ibuf->y))
		brush_painter_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos);
}
Пример #3
0
static void paint_2d_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const bool is_torus)
{
    int x, y, count, xi, yi, xo, yo;
    int out_off[2], in_off[2], dim[2];
    float outrgb[4];

    dim[0] = ibufb->x;
    dim[1] = ibufb->y;
    in_off[0] = pos[0];
    in_off[1] = pos[1];
    out_off[0] = out_off[1] = 0;

    if (!is_torus) {
        IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
                     &out_off[1], &dim[0], &dim[1]);

        if ((dim[0] == 0) || (dim[1] == 0))
            return;
    }

    for (y = 0; y < dim[1]; y++) {
        for (x = 0; x < dim[0]; x++) {
            /* get input pixel */
            xi = in_off[0] + x;
            yi = in_off[1] + y;

            count = 1;
            paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, outrgb);

            count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi - 1, outrgb, is_torus);
            count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi, outrgb, is_torus);
            count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi + 1, outrgb, is_torus);

            count += paint_2d_ibuf_add_if(ibuf, xi, yi - 1, outrgb, is_torus);
            count += paint_2d_ibuf_add_if(ibuf, xi, yi + 1, outrgb, is_torus);

            count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi - 1, outrgb, is_torus);
            count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi, outrgb, is_torus);
            count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi + 1, outrgb, is_torus);

            mul_v4_fl(outrgb, 1.0f / (float)count);

            /* write into brush buffer */
            xo = out_off[0] + x;
            yo = out_off[1] + y;
            paint_2d_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb);
        }
    }
}
Пример #4
0
static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
{
    /* note: allocImbuf returns zero'd memory, so regions outside image will
     * have zero alpha, and hence not be blended onto the image */
    int w = ibufb->x, h = ibufb->y, destx = 0, desty = 0, srcx = pos[0], srcy = pos[1];
    ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);

    IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
    IMB_rectblend(clonebuf, clonebuf, ibufb, NULL, NULL, 0, destx, desty, destx, desty, destx, desty, w, h,
                  IMB_BLEND_COPY_ALPHA);
    IMB_rectblend(clonebuf, clonebuf, ibuf, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h,
                  IMB_BLEND_COPY_RGB);

    return clonebuf;
}
Пример #5
0
static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf, short tile)
{
	int destx = region->destx;
	int desty = region->desty;
	int srcx = region->srcx;
	int srcy = region->srcy;
	int width = region->width;
	int height = region->height;
	int origw, origh, w, h, tot = 0;

	/* convert destination and source coordinates to be within image */
	if (tile & PAINT_TILE_X) {
		destx = destx % dbuf->x;
		if (destx < 0) destx += dbuf->x;
		srcx = srcx % sbuf->x;
		if (srcx < 0) srcx += sbuf->x;
	}
	if (tile & PAINT_TILE_Y) {
		desty = desty % dbuf->y;
		if (desty < 0) desty += dbuf->y;
		srcy = srcy % sbuf->y;
		if (srcy < 0) srcy += sbuf->y;
	}
	/* clip width of blending area to destination imbuf, to avoid writing the
	 * same pixel twice */
	origw = w = (width > dbuf->x) ? dbuf->x : width;
	origh = h = (height > dbuf->y) ? dbuf->y : height;

	/* clip within image */
	IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h);
	paint_2d_set_region(&region[tot++], destx, desty, srcx, srcy, w, h);

	/* do 3 other rects if needed */
	if ((tile & PAINT_TILE_X) && w < origw)
		paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h);
	if ((tile & PAINT_TILE_Y) && h < origh)
		paint_2d_set_region(&region[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h);
	if ((tile & PAINT_TILE_X) && (tile & PAINT_TILE_Y) && (w < origw) && (h < origh))
		paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, (desty + h) % dbuf->y, (srcx + w) % sbuf->x, (srcy + h) % sbuf->y, origw - w, origh - h);

	return tot;
}
Пример #6
0
static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short tile)
{
	bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
	float threshold = s->brush->sharp_threshold;
	int x, y, xi, yi, xo, yo, xk, yk;
	float count;
	int out_off[2], in_off[2], dim[2];
	int diff_pos[2];
	float outrgb[4];
	float rgba[4];
	BlurKernel *kernel = s->blurkernel;

	dim[0] = ibufb->x;
	dim[1] = ibufb->y;
	in_off[0] = pos[0];
	in_off[1] = pos[1];
	out_off[0] = out_off[1] = 0;

	if (!tile) {
		IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
		             &out_off[1], &dim[0], &dim[1]);

		if ((dim[0] == 0) || (dim[1] == 0))
			return;
	}

	/* find offset inside mask buffers to sample them */
	sub_v2_v2v2_int(diff_pos, out_off, in_off);

	for (y = 0; y < dim[1]; y++) {
		for (x = 0; x < dim[0]; x++) {
			/* get input pixel */
			xi = in_off[0] + x;
			yi = in_off[1] + y;

			count = 0.0;
			if (tile) {
				paint_2d_ibuf_tile_convert(ibuf, &xi, &yi, tile);
				if (xi < ibuf->x && xi >= 0 && yi < ibuf->y && yi >= 0)
					paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
				else
					zero_v4(rgba);
			}
			else {
				/* coordinates have been clipped properly here, it should be safe to do this */
				paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
			}
			zero_v4(outrgb);

			for (yk = 0; yk < kernel->side; yk++) {
				for (xk = 0; xk < kernel->side; xk++) {
					count += paint_2d_ibuf_add_if(ibuf, xi + xk - kernel->pixel_len,
					                               yi + yk - kernel->pixel_len, outrgb, tile,
					                               kernel->wdata[xk + yk * kernel->side]);
				}
			}

			if (count > 0.0f) {
				mul_v4_fl(outrgb, 1.0f / (float)count);

				if (sharpen) {
					/* subtract blurred image from normal image gives high pass filter */
					sub_v3_v3v3(outrgb, rgba, outrgb);

					/* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
					 * colored speckles appearing in final image, and also to check for threshold */
					outrgb[0] = outrgb[1] = outrgb[2] = IMB_colormanagement_get_luminance(outrgb);
					if (fabsf(outrgb[0]) > threshold) {
						float mask = BKE_brush_alpha_get(s->scene, s->brush);
						float alpha = rgba[3];
						rgba[3] = outrgb[3] = mask;

						/* add to enhance edges */
						blend_color_add_float(outrgb, rgba, outrgb);
						outrgb[3] = alpha;
					}
					else
						copy_v4_v4(outrgb, rgba);
				}
			}
			else
				copy_v4_v4(outrgb, rgba);
			/* write into brush buffer */
			xo = out_off[0] + x;
			yo = out_off[1] + y;
			paint_2d_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb);
		}
	}
}
Пример #7
0
/**
 * Update the brush mask image by trying to reuse the cached texture result.
 * This can be considerably faster for brushes that change size due to pressure or
 * textures that stick to the surface where only part of the pixels are new
 */
static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, const float pos[2], int diameter)
{
	BrushPainterCache *cache = &painter->cache;
	unsigned short *tex_mask_old;
	int destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;

	/* create brush image buffer if it didn't exist yet */
	if (!cache->tex_mask)
		cache->tex_mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");

	/* create new texture image buffer with coordinates relative to old */
	tex_mask_old = cache->tex_mask_old;
	cache->tex_mask_old = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");

	if (tex_mask_old) {
		ImBuf maskibuf;
		ImBuf maskibuf_old;
		maskibuf.x = maskibuf.y = diameter;
		maskibuf_old.x = cache->tex_mask_old_w;
		maskibuf_old.y = cache->tex_mask_old_h;

		srcx = srcy = 0;
		w = cache->tex_mask_old_w;
		h = cache->tex_mask_old_h;
		destx = (int)painter->lastpaintpos[0] - (int)pos[0]  + (diameter / 2 - w / 2);
		desty = (int)painter->lastpaintpos[1] - (int)pos[1]  + (diameter / 2 - h / 2);

		/* hack, use temporary rects so that clipping works */
		IMB_rectclip(&maskibuf, &maskibuf_old, &destx, &desty, &srcx, &srcy, &w, &h);
	}
	else {
		srcx = srcy = 0;
		destx = desty = 0;
		w = h = 0;
	}

	x1 = min_ii(destx, diameter);
	y1 = min_ii(desty, diameter);
	x2 = min_ii(destx + w, diameter);
	y2 = min_ii(desty + h, diameter);

	/* blend existing texture in new position */
	if ((x1 < x2) && (y1 < y2))
		brush_painter_mask_imbuf_update(painter, tex_mask_old, x1, y1, x2, y2, srcx, srcy, diameter);

	if (tex_mask_old)
		MEM_freeN(tex_mask_old);

	/* sample texture in new areas */
	if ((0 < x1) && (0 < diameter))
		brush_painter_mask_imbuf_update(painter, NULL, 0, 0, x1, diameter, 0, 0, diameter);
	if ((x2 < diameter) && (0 < diameter))
		brush_painter_mask_imbuf_update(painter, NULL, x2, 0, diameter, diameter, 0, 0, diameter);
	if ((x1 < x2) && (0 < y1))
		brush_painter_mask_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0, diameter);
	if ((x1 < x2) && (y2 < diameter))
		brush_painter_mask_imbuf_update(painter, NULL, x1, y2, x2, diameter, 0, 0, diameter);

	/* through with sampling, now update sizes */
	cache->tex_mask_old_w = diameter;
	cache->tex_mask_old_h = diameter;
}
Пример #8
0
void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, 
	int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode)
{
	unsigned int *drect = NULL, *srect = NULL, *dr, *sr;
	float *drectf = NULL, *srectf = NULL, *drf, *srf;
	int do_float, do_char, srcskip, destskip, x;

	if (dbuf == NULL) return;

	IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &width, &height);

	if (width == 0 || height == 0) return;
	if (sbuf && sbuf->channels!=4) return;
	if (dbuf->channels!=4) return;
	
	do_char = (sbuf && sbuf->rect && dbuf->rect);
	do_float = (sbuf && sbuf->rect_float && dbuf->rect_float);

	if (do_char) drect = dbuf->rect + desty * dbuf->x + destx;
	if (do_float) drectf = dbuf->rect_float + (desty * dbuf->x + destx)*4;

	destskip = dbuf->x;

	if (sbuf) {
		if (do_char) srect = sbuf->rect + srcy * sbuf->x + srcx;
		if (do_float) srectf = sbuf->rect_float + (srcy * sbuf->x + srcx)*4;
		srcskip = sbuf->x;
	} else {
		srect = drect;
		srectf = drectf;
		srcskip = destskip;
	}

	if (mode == IMB_BLEND_COPY) {
		/* copy */
		for (;height > 0; height--) {
			if (do_char) {
				memcpy(drect,srect, width * sizeof(int));
				drect += destskip;
				srect += srcskip;
			}

			if (do_float) {
				memcpy(drectf,srectf, width * sizeof(float) * 4);
				drectf += destskip*4;
				srectf += srcskip*4;
			}
		}
	}
	else if (mode == IMB_BLEND_COPY_RGB) {
		/* copy rgb only */
		for (;height > 0; height--) {
			if (do_char) {
				dr = drect;
				sr = srect;
				for (x=width; x > 0; x--, dr++, sr++) {
					((char*)dr)[0]= ((char*)sr)[0];
					((char*)dr)[1]= ((char*)sr)[1];
					((char*)dr)[2]= ((char*)sr)[2];
				}
				drect += destskip;
				srect += srcskip;
			}

			if (do_float) {
				drf = drectf;
				srf = srectf;
				for (x=width; x > 0; x--, drf+=4, srf+=4) {
					drf[0]= srf[0];
					drf[1]= srf[1];
					drf[2]= srf[2];
				}
				drectf += destskip*4;
				srectf += srcskip*4;
			}
		}
	}
	else if (mode == IMB_BLEND_COPY_ALPHA) {
		/* copy alpha only */
		for (;height > 0; height--) {
			if (do_char) {
				dr = drect;
				sr = srect;
				for (x=width; x > 0; x--, dr++, sr++)
					((char*)dr)[3]= ((char*)sr)[3];
				drect += destskip;
				srect += srcskip;
			}

			if (do_float) {
				drf = drectf;
				srf = srectf;
				for (x=width; x > 0; x--, drf+=4, srf+=4)
					drf[3]= srf[3];
				drectf += destskip*4;
				srectf += srcskip*4;
			}
		}
	}
	else {
		/* blend */
		for (;height > 0; height--) {
			if (do_char) {
				dr = drect;
				sr = srect;
				for (x=width; x > 0; x--, dr++, sr++)
					*dr = IMB_blend_color(*dr, *sr, ((char*)sr)[3], mode);

				drect += destskip;
				srect += srcskip;
			}

			if (do_float) {
				drf = drectf;
				srf = srectf;
				for (x=width; x > 0; x--, drf+=4, srf+=4)
					IMB_blend_color_float(drf, drf, srf, srf[3], mode);

				drectf += destskip*4;
				srectf += srcskip*4;
			}		
		}
	}
}