Example #1
0
void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], float jitterpos[2])
{
	float rand_pos[2];
	float spread;
	int diameter;

	do {
		rand_pos[0] = BLI_rng_get_float(brush_rng) - 0.5f;
		rand_pos[1] = BLI_rng_get_float(brush_rng) - 0.5f;
	} while (len_squared_v2(rand_pos) > SQUARE(0.5f));


	if (brush->flag & BRUSH_ABSOLUTE_JITTER) {
		diameter = 2 * brush->jitter_absolute;
		spread = 1.0;
	}
	else {
		diameter = 2 * BKE_brush_size_get(scene, brush);
		spread = brush->jitter;
	}
	/* find random position within a circle of diameter 1 */
	jitterpos[0] = pos[0] + 2 * rand_pos[0] * diameter * spread;
	jitterpos[1] = pos[1] + 2 * rand_pos[1] * diameter * spread;
}
Example #2
0
void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], float jitterpos[2])
{
	int use_jitter = (brush->flag & BRUSH_ABSOLUTE_JITTER) ?
		(brush->jitter_absolute != 0) : (brush->jitter != 0);

	/* jitter-ed brush gives weird and unpredictable result for this
	 * kinds of stroke, so manually disable jitter usage (sergey) */
	use_jitter &= (brush->flag & (BRUSH_DRAG_DOT | BRUSH_ANCHORED)) == 0;

	if (use_jitter) {
		float rand_pos[2];
		float spread;
		int diameter;

		do {
			rand_pos[0] = BLI_rng_get_float(brush_rng) - 0.5f;
			rand_pos[1] = BLI_rng_get_float(brush_rng) - 0.5f;
		} while (len_v2(rand_pos) > 0.5f);


		if (brush->flag & BRUSH_ABSOLUTE_JITTER) {
			diameter = 2 * brush->jitter_absolute;
			spread = 1.0;
		}
		else {
			diameter = 2 * BKE_brush_size_get(scene, brush);
			spread = brush->jitter;
		}
		/* find random position within a circle of diameter 1 */
		jitterpos[0] = pos[0] + 2 * rand_pos[0] * diameter * spread;
		jitterpos[1] = pos[1] + 2 * rand_pos[1] * diameter * spread;
	}
	else {
		copy_v2_v2(jitterpos, pos);
	}
}
Example #3
0
float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
                               const float point[2],
                               const int thread,
                               struct ImagePool *pool)
{
	UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
	MTex *mtex = &br->mask_mtex;
	float rgba[4], intensity;

	if (!mtex->tex) {
		return 1.0f;
	}
	if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) {
		float rotation = -mtex->rot;
		float point_2d[2] = {point[0], point[1]};
		float x, y;
		float co[3];

		x = point_2d[0] - br->mask_stencil_pos[0];
		y = point_2d[1] - br->mask_stencil_pos[1];

		if (rotation > 0.001f || rotation < -0.001f) {
			const float angle    = atan2f(y, x) + rotation;
			const float flen     = sqrtf(x * x + y * y);

			x = flen * cosf(angle);
			y = flen * sinf(angle);
		}

		if (fabsf(x) > br->mask_stencil_dimension[0] || fabsf(y) > br->mask_stencil_dimension[1]) {
			zero_v4(rgba);
			return 0.0f;
		}
		x /= (br->mask_stencil_dimension[0]);
		y /= (br->mask_stencil_dimension[1]);

		co[0] = x;
		co[1] = y;
		co[2] = 0.0f;

		externtex(mtex, co, &intensity,
		          rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
	}
	else {
		float rotation = -mtex->rot;
		float point_2d[2] = {point[0], point[1]};
		float x = 0.0f, y = 0.0f; /* Quite warnings */
		float invradius = 1.0f; /* Quite warnings */
		float co[3];

		if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
			/* keep coordinates relative to mouse */

			rotation += ups->brush_rotation_sec;

			x = point_2d[0] - ups->mask_tex_mouse[0];
			y = point_2d[1] - ups->mask_tex_mouse[1];

			/* use pressure adjusted size for fixed mode */
			invradius = 1.0f / ups->pixel_radius;
		}
		else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
			/* leave the coordinates relative to the screen */

			/* use unadjusted size for tiled mode */
			invradius = 1.0f / BKE_brush_size_get(scene, br);

			x = point_2d[0];
			y = point_2d[1];
		}
		else if (mtex->brush_map_mode == MTEX_MAP_MODE_RANDOM) {
			rotation += ups->brush_rotation_sec;
			/* these contain a random coordinate */
			x = point_2d[0] - ups->mask_tex_mouse[0];
			y = point_2d[1] - ups->mask_tex_mouse[1];

			invradius = 1.0f / ups->pixel_radius;
		}

		x *= invradius;
		y *= invradius;

		/* it is probably worth optimizing for those cases where
		 * the texture is not rotated by skipping the calls to
		 * atan2, sqrtf, sin, and cos. */
		if (rotation > 0.001f || rotation < -0.001f) {
			const float angle    = atan2f(y, x) + rotation;
			const float flen     = sqrtf(x * x + y * y);

			x = flen * cosf(angle);
			y = flen * sinf(angle);
		}

		co[0] = x;
		co[1] = y;
		co[2] = 0.0f;

		externtex(mtex, co, &intensity,
		          rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
	}

	CLAMP(intensity, 0.0f, 1.0f);

	switch (br->mask_pressure) {
		case BRUSH_MASK_PRESSURE_CUTOFF:
			intensity  = ((1.0f - intensity) < ups->size_pressure_value) ? 1.0f : 0.0f;
			break;
		case BRUSH_MASK_PRESSURE_RAMP:
			intensity = ups->size_pressure_value + intensity * (1.0f - ups->size_pressure_value);
			break;
		default:
			break;
	}

	return intensity;
}
Example #4
0
/* Generic texture sampler for 3D painting systems. point has to be either in
 * region space mouse coordinates, or 3d world coordinates for 3D mapping.
 *
 * rgba outputs straight alpha. */
float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br,
                              const float point[3],
                              float rgba[4], const int thread,
                              struct ImagePool *pool)
{
	UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
	MTex *mtex = &br->mtex;
	float intensity = 1.0;
	bool hasrgb = false;

	if (!mtex->tex) {
		intensity = 1;
	}
	else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
		/* Get strength by feeding the vertex
		 * location directly into a texture */
		hasrgb = externtex(mtex, point, &intensity,
		                   rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
	}
	else if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) {
		float rotation = -mtex->rot;
		float point_2d[2] = {point[0], point[1]};
		float x, y;
		float co[3];

		x = point_2d[0] - br->stencil_pos[0];
		y = point_2d[1] - br->stencil_pos[1];

		if (rotation > 0.001f || rotation < -0.001f) {
			const float angle    = atan2f(y, x) + rotation;
			const float flen     = sqrtf(x * x + y * y);

			x = flen * cosf(angle);
			y = flen * sinf(angle);
		}

		if (fabsf(x) > br->stencil_dimension[0] || fabsf(y) > br->stencil_dimension[1]) {
			zero_v4(rgba);
			return 0.0f;
		}
		x /= (br->stencil_dimension[0]);
		y /= (br->stencil_dimension[1]);

		co[0] = x;
		co[1] = y;
		co[2] = 0.0f;

		hasrgb = externtex(mtex, co, &intensity,
		                   rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
	}
	else {
		float rotation = -mtex->rot;
		float point_2d[2] = {point[0], point[1]};
		float x = 0.0f, y = 0.0f; /* Quite warnings */
		float invradius = 1.0f; /* Quite warnings */
		float co[3];

		if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
			/* keep coordinates relative to mouse */

			rotation += ups->brush_rotation;

			x = point_2d[0] - ups->tex_mouse[0];
			y = point_2d[1] - ups->tex_mouse[1];

			/* use pressure adjusted size for fixed mode */
			invradius = 1.0f / ups->pixel_radius;
		}
		else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
			/* leave the coordinates relative to the screen */

			/* use unadjusted size for tiled mode */
			invradius = 1.0f / BKE_brush_size_get(scene, br);

			x = point_2d[0];
			y = point_2d[1];
		}
		else if (mtex->brush_map_mode == MTEX_MAP_MODE_RANDOM) {
			rotation += ups->brush_rotation;
			/* these contain a random coordinate */
			x = point_2d[0] - ups->tex_mouse[0];
			y = point_2d[1] - ups->tex_mouse[1];

			invradius = 1.0f / ups->pixel_radius;
		}

		x *= invradius;
		y *= invradius;

		/* it is probably worth optimizing for those cases where
		 * the texture is not rotated by skipping the calls to
		 * atan2, sqrtf, sin, and cos. */
		if (rotation > 0.001f || rotation < -0.001f) {
			const float angle    = atan2f(y, x) + rotation;
			const float flen     = sqrtf(x * x + y * y);

			x = flen * cosf(angle);
			y = flen * sinf(angle);
		}

		co[0] = x;
		co[1] = y;
		co[2] = 0.0f;

		hasrgb = externtex(mtex, co, &intensity,
		                   rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
	}

	intensity += br->texture_sample_bias;

	if (!hasrgb) {
		rgba[0] = intensity;
		rgba[1] = intensity;
		rgba[2] = intensity;
		rgba[3] = 1.0f;
	}
	/* For consistency, sampling always returns color in linear space */
	else if (ups->do_linear_conversion) {
		IMB_colormanagement_colorspace_to_scene_linear_v3(rgba, ups->colorspace);
	}

	return intensity;
}
Example #5
0
static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, const float pos[2], const float mouse[2])
{
    const Scene *scene = painter->scene;
    UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
    Brush *brush = painter->brush;
    BrushPainterCache *cache = &painter->cache;
    const int diameter = 2 * BKE_brush_size_get(scene, brush);
    const int size = (cache->size) ? cache->size : diameter;
    const float alpha = BKE_brush_alpha_get(scene, brush);
    const bool use_masking = painter->cache.use_masking;

    bool do_random = false;
    bool do_partial_update = false;
    bool do_view = false;
    float tex_rotation = -brush->mtex.rot;
    float mask_rotation = -brush->mask_mtex.rot;

    /* determine how can update based on textures used */
    if (painter->cache.is_texbrush) {
        if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
            do_view = true;
            tex_rotation += ups->brush_rotation;
        }
        else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
            do_random = true;
        else
            do_partial_update = true;

        brush_painter_2d_tex_mapping(s, size, painter->startpaintpos, pos, mouse,
                                     brush->mtex.brush_map_mode, &painter->tex_mapping);
    }

    if (painter->cache.is_maskbrush) {
        if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
            do_view = true;
            mask_rotation += ups->brush_rotation;
        }
        else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
            do_random = true;
        else
            do_partial_update = true;

        brush_painter_2d_tex_mapping(s, size, painter->startpaintpos, pos, mouse,
                                     brush->mask_mtex.brush_map_mode, &painter->mask_mapping);
    }

    if (do_view || do_random)
        do_partial_update = false;

    painter->pool = BKE_image_pool_new();

    /* detect if we need to recreate image brush buffer */
    if (diameter != cache->lastsize ||
            alpha != cache->lastalpha ||
            brush->jitter != cache->lastjitter ||
            tex_rotation != cache->last_tex_rotation ||
            mask_rotation != cache->last_mask_rotation ||
            do_random)
    {
        if (cache->ibuf) {
            IMB_freeImBuf(cache->ibuf);
            cache->ibuf = NULL;
        }
        if (cache->mask) {
            MEM_freeN(cache->mask);
            cache->mask = NULL;
        }

        if (do_partial_update) {
            /* do partial update of texture + recreate mask */
            cache->mask = brush_painter_mask_new(painter, size);
            brush_painter_imbuf_partial_update(painter, pos);
        }
        else {
            /* create brush and mask from scratch */
            if (use_masking)
                cache->mask = brush_painter_mask_new(painter, size);
            cache->ibuf = brush_painter_imbuf_new(painter, size);
        }

        cache->lastsize = diameter;
        cache->lastalpha = alpha;
        cache->lastjitter = brush->jitter;
        cache->last_tex_rotation = tex_rotation;
        cache->last_mask_rotation = mask_rotation;
    }
    else if (do_partial_update) {
        /* do only partial update of texture */
        int dx = (int)painter->lastpaintpos[0] - (int)pos[0];
        int dy = (int)painter->lastpaintpos[1] - (int)pos[1];

        if ((dx != 0) || (dy != 0)) {
            brush_painter_imbuf_partial_update(painter, pos);
        }
    }

    BKE_image_pool_free(painter->pool);
    painter->pool = NULL;
}
Example #6
0
/* create imbuf with brush color */
static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size)
{
    Scene *scene = painter->scene;
    Brush *brush = painter->brush;

    rctf tex_mapping = painter->tex_mapping;
    rctf mask_mapping = painter->mask_mapping;
    struct ImagePool *pool = painter->pool;

    bool use_masking = painter->cache.use_masking;
    bool use_color_correction = painter->cache.use_color_correction;
    bool use_float = painter->cache.use_float;
    bool is_texbrush = painter->cache.is_texbrush;
    bool is_maskbrush = painter->cache.is_maskbrush;

    float alpha = (use_masking) ? 1.0f : BKE_brush_alpha_get(scene, brush);
    int radius = BKE_brush_size_get(scene, brush);
    int xoff = -size * 0.5f + 0.5f;
    int yoff = -size * 0.5f + 0.5f;

    int x, y, thread = 0;
    float brush_rgb[3];

    /* allocate image buffer */
    ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_rectfloat : IB_rect);

    /* get brush color */
    if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
        copy_v3_v3(brush_rgb, brush->rgb);

        if (use_color_correction)
            srgb_to_linearrgb_v3_v3(brush_rgb, brush_rgb);
    }
    else {
        brush_rgb[0] = 1.0f;
        brush_rgb[1] = 1.0f;
        brush_rgb[2] = 1.0f;
    }

    /* fill image buffer */
    for (y = 0; y < size; y++) {
        for (x = 0; x < size; x++) {
            /* sample texture and multiply with brush color */
            float texco[3], rgba[4];

            if (is_texbrush) {
                brush_imbuf_tex_co(&tex_mapping, x, y, texco);
                BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool);
                /* TODO(sergey): Support texture paint color space. */
                if (!use_float) {
                    linearrgb_to_srgb_v3_v3(rgba, rgba);
                }
                mul_v3_v3(rgba, brush_rgb);
            }
            else {
                copy_v3_v3(rgba, brush_rgb);
                rgba[3] = 1.0f;
            }

            if (is_maskbrush) {
                brush_imbuf_tex_co(&mask_mapping, x, y, texco);
                rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
            }

            /* when not using masking, multiply in falloff and strength */
            if (!use_masking) {
                float xy[2] = {x + xoff, y + yoff};
                float len = len_v2(xy);

                rgba[3] *= alpha * BKE_brush_curve_strength_clamp(brush, len, radius);
            }

            if (use_float) {
                /* write to float pixel */
                float *dstf = ibuf->rect_float + (y * size + x) * 4;
                mul_v3_v3fl(dstf, rgba, rgba[3]); /* premultiply */
                dstf[3] = rgba[3];
            }
            else {
                /* write to byte pixel */
                unsigned char *dst = (unsigned char *)ibuf->rect + (y * size + x) * 4;

                rgb_float_to_uchar(dst, rgba);
                dst[3] = FTOCHAR(rgba[3]);
            }
        }
    }

    return ibuf;
}
Example #7
0
int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float pos[2], double time, float pressure,
                            void *user, int use_color_correction)
{
	Scene *scene = painter->scene;
	Brush *brush = painter->brush;
	int totpaintops = 0;

	if (pressure == 0.0f) {
		if (painter->lastpressure) // XXX - hack, operator misses
			pressure = painter->lastpressure;
		else
			pressure = 1.0f;    /* zero pressure == not using tablet */
	}
	if (painter->firsttouch) {
		/* paint exactly once on first touch */
		painter->startpaintpos[0] = pos[0];
		painter->startpaintpos[1] = pos[1];

		brush_pressure_apply(painter, brush, pressure);
		if (painter->cache.enabled)
			brush_painter_refresh_cache(painter, pos, use_color_correction);
		totpaintops += func(user, painter->cache.ibuf, pos, pos);
		
		painter->lasttime = time;
		painter->firsttouch = 0;
		painter->lastpaintpos[0] = pos[0];
		painter->lastpaintpos[1] = pos[1];
	}
#if 0
	else if (painter->brush->flag & BRUSH_AIRBRUSH) {
		float spacing, step, paintpos[2], dmousepos[2], len;
		double starttime, curtime = time;

		/* compute brush spacing adapted to brush size */
		spacing = brush->rate; //radius*brush->spacing * 0.01f;

		/* setup starting time, direction vector and accumulated time */
		starttime = painter->accumtime;
		sub_v2_v2v2(dmousepos, pos, painter->lastmousepos);
		len = normalize_v2(dmousepos);
		painter->accumtime += curtime - painter->lasttime;

		/* do paint op over unpainted time distance */
		while (painter->accumtime >= spacing) {
			step = (spacing - starttime) * len;
			paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step;
			paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step;

			if (painter->cache.enabled)
				brush_painter_refresh_cache(painter);
			totpaintops += func(user, painter->cache.ibuf,
			                    painter->lastpaintpos, paintpos);

			painter->lastpaintpos[0] = paintpos[0];
			painter->lastpaintpos[1] = paintpos[1];
			painter->accumtime -= spacing;
			starttime -= spacing;
		}
		
		painter->lasttime = curtime;
	}
#endif
	else {
		float startdistance, spacing, step, paintpos[2], dmousepos[2], finalpos[2];
		float t, len, press;
		const int radius = BKE_brush_size_get(scene, brush);

		/* compute brush spacing adapted to brush radius, spacing may depend
		 * on pressure, so update it */
		brush_pressure_apply(painter, brush, painter->lastpressure);
		spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f;

		/* setup starting distance, direction vector and accumulated distance */
		startdistance = painter->accumdistance;
		sub_v2_v2v2(dmousepos, pos, painter->lastmousepos);
		len = normalize_v2(dmousepos);
		painter->accumdistance += len;

		if (brush->flag & BRUSH_SPACE) {
			/* do paint op over unpainted distance */
			while ((len > 0.0f) && (painter->accumdistance >= spacing)) {
				step = spacing - startdistance;
				paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step;
				paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step;

				t = step / len;
				press = (1.0f - t) * painter->lastpressure + t * pressure;
				brush_pressure_apply(painter, brush, press);
				spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f;

				BKE_brush_jitter_pos(scene, brush, paintpos, finalpos);

				if (painter->cache.enabled)
					brush_painter_refresh_cache(painter, finalpos, use_color_correction);

				totpaintops +=
				    func(user, painter->cache.ibuf, painter->lastpaintpos, finalpos);

				painter->lastpaintpos[0] = paintpos[0];
				painter->lastpaintpos[1] = paintpos[1];
				painter->accumdistance -= spacing;
				startdistance -= spacing;
			}
		}
		else {
			BKE_brush_jitter_pos(scene, brush, pos, finalpos);

			if (painter->cache.enabled)
				brush_painter_refresh_cache(painter, finalpos, use_color_correction);

			totpaintops += func(user, painter->cache.ibuf, pos, finalpos);

			painter->lastpaintpos[0] = pos[0];
			painter->lastpaintpos[1] = pos[1];
			painter->accumdistance = 0;
		}

		/* do airbrush paint ops, based on the number of paint ops left over
		 * from regular painting. this is a temporary solution until we have
		 * accurate time stamps for mouse move events */
		if (brush->flag & BRUSH_AIRBRUSH) {
			double curtime = time;
			double painttime = brush->rate * totpaintops;

			painter->accumtime += curtime - painter->lasttime;
			if (painter->accumtime <= painttime)
				painter->accumtime = 0.0;
			else
				painter->accumtime -= painttime;

			while (painter->accumtime >= (double)brush->rate) {
				brush_pressure_apply(painter, brush, pressure);

				BKE_brush_jitter_pos(scene, brush, pos, finalpos);

				if (painter->cache.enabled)
					brush_painter_refresh_cache(painter, finalpos, use_color_correction);

				totpaintops +=
				    func(user, painter->cache.ibuf, painter->lastmousepos, finalpos);
				painter->accumtime -= (double)brush->rate;
			}

			painter->lasttime = curtime;
		}
	}

	painter->lastmousepos[0] = pos[0];
	painter->lastmousepos[1] = pos[1];
	painter->lastpressure = pressure;

	BKE_brush_alpha_set(scene, brush, painter->startalpha);
	BKE_brush_size_set(scene, brush, painter->startsize);
	brush->jitter = painter->startjitter;
	brush->spacing = painter->startspacing;

	return totpaintops;
}
Example #8
0
static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf,
                                     int x, int y, int w, int h, int xt, int yt,
                                     const float pos[2])
{
	Scene *scene = painter->scene;
	Brush *brush = painter->brush;
	ImBuf *ibuf, *maskibuf, *texibuf;
	float *bf, *mf, *tf, *otf = NULL, xoff, yoff, xy[2], rgba[4];
	unsigned char *b, *m, *t, *ot = NULL;
	int dotexold, origx = x, origy = y;
	const int radius = BKE_brush_size_get(painter->scene, brush);

	xoff = -radius + 0.5f;
	yoff = -radius + 0.5f;
	xoff += (int)pos[0] - (int)painter->startpaintpos[0];
	yoff += (int)pos[1] - (int)painter->startpaintpos[1];

	ibuf = painter->cache.ibuf;
	texibuf = painter->cache.texibuf;
	maskibuf = painter->cache.maskibuf;

	dotexold = (oldtexibuf != NULL);

	/* not sure if it's actually needed or it's a mistake in coords/sizes
	 * calculation in brush_painter_fixed_tex_partial_update(), but without this
	 * limitation memory gets corrupted at fast strokes with quite big spacing (sergey) */
	w = min_ii(w, ibuf->x);
	h = min_ii(h, ibuf->y);

	if (painter->cache.flt) {
		for (; y < h; y++) {
			bf = ibuf->rect_float + (y * ibuf->x + origx) * 4;
			tf = texibuf->rect_float + (y * texibuf->x + origx) * 4;
			mf = maskibuf->rect_float + (y * maskibuf->x + origx) * 4;

			if (dotexold)
				otf = oldtexibuf->rect_float + ((y - origy + yt) * oldtexibuf->x + xt) * 4;

			for (x = origx; x < w; x++, bf += 4, mf += 4, tf += 4) {
				if (dotexold) {
					copy_v3_v3(tf, otf);
					tf[3] = otf[3];
					otf += 4;
				}
				else {
					xy[0] = x + xoff;
					xy[1] = y + yoff;

					BKE_brush_sample_tex(scene, brush, xy, tf, 0);
				}

				bf[0] = tf[0] * mf[0];
				bf[1] = tf[1] * mf[1];
				bf[2] = tf[2] * mf[2];
				bf[3] = tf[3] * mf[3];
			}
		}
	}
	else {
		for (; y < h; y++) {
			b = (unsigned char *)ibuf->rect + (y * ibuf->x + origx) * 4;
			t = (unsigned char *)texibuf->rect + (y * texibuf->x + origx) * 4;
			m = (unsigned char *)maskibuf->rect + (y * maskibuf->x + origx) * 4;

			if (dotexold)
				ot = (unsigned char *)oldtexibuf->rect + ((y - origy + yt) * oldtexibuf->x + xt) * 4;

			for (x = origx; x < w; x++, b += 4, m += 4, t += 4) {
				if (dotexold) {
					t[0] = ot[0];
					t[1] = ot[1];
					t[2] = ot[2];
					t[3] = ot[3];
					ot += 4;
				}
				else {
					xy[0] = x + xoff;
					xy[1] = y + yoff;

					BKE_brush_sample_tex(scene, brush, xy, rgba, 0);
					rgba_float_to_uchar(t, rgba);
				}

				b[0] = t[0] * m[0] / 255;
				b[1] = t[1] * m[1] / 255;
				b[2] = t[2] * m[2] / 255;
				b[3] = t[3] * m[3] / 255;
			}
		}
	}
}
Example #9
0
/* TODO, use define for 'texfall' arg */
void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texfall, int bufsize, ImBuf **outbuf, int use_color_correction)
{
    ImBuf *ibuf;
    float xy[2], rgba[4], *dstf;
    int x, y, rowbytes, xoff, yoff, imbflag;
    const int radius = BKE_brush_size_get(scene, brush);
    unsigned char *dst, crgb[3];
    const float alpha = BKE_brush_alpha_get(scene, brush);
    float brush_rgb[3];

    imbflag = (flt) ? IB_rectfloat : IB_rect;
    xoff = -bufsize / 2.0f + 0.5f;
    yoff = -bufsize / 2.0f + 0.5f;
    rowbytes = bufsize * 4;

    if (*outbuf)
        ibuf = *outbuf;
    else
        ibuf = IMB_allocImBuf(bufsize, bufsize, 32, imbflag);

    if (flt) {
        copy_v3_v3(brush_rgb, brush->rgb);
        if (use_color_correction) {
            srgb_to_linearrgb_v3_v3(brush_rgb, brush_rgb);
        }

        for (y = 0; y < ibuf->y; y++) {
            dstf = ibuf->rect_float + y * rowbytes;

            for (x = 0; x < ibuf->x; x++, dstf += 4) {
                xy[0] = x + xoff;
                xy[1] = y + yoff;

                if (texfall == 0) {
                    copy_v3_v3(dstf, brush_rgb);
                    dstf[3] = alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius);
                }
                else if (texfall == 1) {
                    BKE_brush_sample_tex(scene, brush, xy, dstf, 0);
                }
                else {
                    BKE_brush_sample_tex(scene, brush, xy, rgba, 0);
                    mul_v3_v3v3(dstf, rgba, brush_rgb);
                    dstf[3] = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius);
                }
            }
        }
    }
    else {
        float alpha_f; /* final float alpha to convert to char */
        rgb_float_to_uchar(crgb, brush->rgb);

        for (y = 0; y < ibuf->y; y++) {
            dst = (unsigned char *)ibuf->rect + y * rowbytes;

            for (x = 0; x < ibuf->x; x++, dst += 4) {
                xy[0] = x + xoff;
                xy[1] = y + yoff;

                if (texfall == 0) {
                    alpha_f = alpha * BKE_brush_curve_strength(brush, len_v2(xy), radius);

                    dst[0] = crgb[0];
                    dst[1] = crgb[1];
                    dst[2] = crgb[2];
                    dst[3] = FTOCHAR(alpha_f);
                }
                else if (texfall == 1) {
                    BKE_brush_sample_tex(scene, brush, xy, rgba, 0);
                    rgba_float_to_uchar(dst, rgba);
                }
                else if (texfall == 2) {
                    BKE_brush_sample_tex(scene, brush, xy, rgba, 0);
                    mul_v3_v3(rgba, brush->rgb);
                    alpha_f = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius);

                    rgb_float_to_uchar(dst, rgba);

                    dst[3] = FTOCHAR(alpha_f);
                }
                else {
                    BKE_brush_sample_tex(scene, brush, xy, rgba, 0);
                    alpha_f = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius);

                    dst[0] = crgb[0];
                    dst[1] = crgb[1];
                    dst[2] = crgb[2];
                    dst[3] = FTOCHAR(alpha_f);
                }
            }
        }
    }

    *outbuf = ibuf;
}