More image painting fixes:

* 2D image painting support for masking to limit the max contribution of a stroke
  to a pixel, to get it working compatible with projection painting. Not strictly
  a bugfix, but the inconsistency here was annoying.

* Fix python errors in Texture Mask panel in image editor, was missing overlay
  options.

* Clamp paint mask to 0..1 in case some texture exceeds it, this could give black
  pixels due to integer overflow.
This commit is contained in:
Brecht Van Lommel 2013-04-30 06:07:42 +00:00
parent b735402c19
commit 63f05576b8
11 changed files with 346 additions and 71 deletions

View File

@ -763,6 +763,12 @@ class IMAGE_PT_tools_mask_texture(BrushButtonsPanel, Panel):
col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
brush_mask_texture_settings(col, brush)
col = layout.column(align=True)
col.active = brush.brush_capabilities.has_overlay
col.label(text="Overlay:")
row = col.row()
if tex_slot_alpha.map_mode != 'STENCIL':
if brush.use_secondary_overlay:
row.prop(brush, "use_secondary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_OFF')

View File

@ -82,7 +82,7 @@ float BKE_brush_sample_tex_2D(const struct Scene *scene, struct Brush *brush, co
float BKE_brush_sample_masktex(const Scene *scene, struct Brush *br, const float point[3],
const int thread, struct ImagePool *pool);
void BKE_brush_imbuf_new(const struct Scene *scene, struct Brush *brush, short flt, short texfalloff, int size,
struct ImBuf **imbuf, int use_color_correction);
struct ImBuf **imbuf, bool use_color_correction, bool use_brush_alpha);
/* texture */
unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side);

View File

@ -828,14 +828,15 @@ float BKE_brush_sample_tex_2D(const Scene *scene, Brush *brush, const float xy[2
/* TODO, use define for 'texfall' arg
* NOTE: only used for 2d brushes currently! */
void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texfall, int bufsize, ImBuf **outbuf, int use_color_correction)
void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texfall, int bufsize,
ImBuf **outbuf, bool use_color_correction, bool use_brush_alpha)
{
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);
const float alpha = (use_brush_alpha)? BKE_brush_alpha_get(scene, brush): 1.0f;
float brush_rgb[3];
imbflag = (flt) ? IB_rectfloat : IB_rect;

View File

@ -372,12 +372,17 @@ MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], co
{
if (src2[3] != 0.0f && src1[3] > 0.0f) {
/* subtract alpha and remap RGB channels to match */
const float alpha = max_ff(src1[3] - src2[3], 0.0f);
const float map_alpha = alpha / src1[3];
float alpha = max_ff(src1[3] - src2[3], 0.0f);
float map_alpha;
dst[0] *= map_alpha;
dst[1] *= map_alpha;
dst[2] *= map_alpha;
if (alpha <= 0.0005f)
alpha = 0.0f;
map_alpha = alpha / src1[3];
dst[0] = src1[0] * map_alpha;
dst[1] = src1[1] * map_alpha;
dst[2] = src1[2] * map_alpha;
dst[3] = alpha;
}
else {
@ -393,12 +398,17 @@ MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], cons
{
if (src2[3] != 0.0f && src1[3] < 1.0f) {
/* add alpha and remap RGB channels to match */
const float alpha = min_ff(src1[3] + src2[3], 1.0f);
const float map_alpha = (src1[3] > 0.0f) ? alpha / src1[3] : 1.0f;
float alpha = min_ff(src1[3] + src2[3], 1.0f);
float map_alpha;
dst[0] *= map_alpha;
dst[1] *= map_alpha;
dst[2] *= map_alpha;
if (alpha >= 1.0f - 0.0005f)
alpha = 1.0f;
map_alpha = (src1[3] > 0.0f) ? alpha / src1[3] : 1.0f;
dst[0] = src1[0] * map_alpha;
dst[1] = src1[1] * map_alpha;
dst[2] = src1[2] * map_alpha;
dst[3] = alpha;
}
else {

View File

@ -101,9 +101,6 @@
#include "paint_intern.h"
#define IMAPAINT_TILE_BITS 6
#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS)
typedef struct UndoImageTile {
struct UndoImageTile *next, *prev;
@ -115,6 +112,9 @@ typedef struct UndoImageTile {
unsigned int *uint;
void *pt;
} rect;
unsigned short *mask;
int x, y;
short source, use_float;
@ -156,18 +156,45 @@ static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int
tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
}
void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
UndoImageTile *tile;
short use_float = ibuf->rect_float ? 1 : 0;
for (tile = lb->first; tile; tile = tile->next) {
if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) {
if (tile->use_float == use_float) {
if (strcmp(tile->idname, ima->id.name) == 0 && strcmp(tile->ibufname, ibuf->name) == 0) {
if (mask) {
/* allocate mask if requested */
if (!tile->mask)
tile->mask = MEM_callocN(sizeof(unsigned short)*IMAPAINT_TILE_SIZE*IMAPAINT_TILE_SIZE, "UndoImageTile.mask");
*mask = tile->mask;
}
return tile->rect.pt;
}
}
}
}
return NULL;
}
void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
UndoImageTile *tile;
int allocsize;
short use_float = ibuf->rect_float ? 1 : 0;
void *data;
for (tile = lb->first; tile; tile = tile->next)
if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source)
if (tile->use_float == use_float)
if (strcmp(tile->idname, ima->id.name) == 0 && strcmp(tile->ibufname, ibuf->name) == 0)
return tile->rect.pt;
/* check if tile is already pushed */
data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, NULL);
if (data)
return data;
if (*tmpibuf == NULL)
*tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
@ -195,6 +222,19 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
return tile->rect.pt;
}
void image_undo_remove_masks(void)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
UndoImageTile *tile;
for (tile = lb->first; tile; tile = tile->next) {
if (tile->mask) {
MEM_freeN(tile->mask);
tile->mask = NULL;
}
}
}
void image_undo_restore(bContext *C, ListBase *lb)
{
Main *bmain = CTX_data_main(C);
@ -276,10 +316,23 @@ void imapaint_clear_partial_redraw(void)
memset(&imapaintpartial, 0, sizeof(imapaintpartial));
}
void imapaint_region_tiles(ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
{
int srcx = 0, srcy = 0;
IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
*tw = ((x + w - 1) >> IMAPAINT_TILE_BITS);
*th = ((y + h - 1) >> IMAPAINT_TILE_BITS);
*tx = (x >> IMAPAINT_TILE_BITS);
*ty = (y >> IMAPAINT_TILE_BITS);
}
void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
{
ImBuf *tmpibuf = NULL;
int srcx = 0, srcy = 0, origx;
int tilex, tiley, tilew, tileh, tx, ty;
int srcx = 0, srcy = 0;
IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
@ -300,14 +353,11 @@ void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
imapaintpartial.y2 = max_ii(imapaintpartial.y2, y + h);
}
w = ((x + w - 1) >> IMAPAINT_TILE_BITS);
h = ((y + h - 1) >> IMAPAINT_TILE_BITS);
origx = (x >> IMAPAINT_TILE_BITS);
y = (y >> IMAPAINT_TILE_BITS);
for (; y <= h; y++)
for (x = origx; x <= w; x++)
image_undo_push_tile(ima, ibuf, &tmpibuf, x, y);
imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
for (ty = tiley; ty <= tileh; ty++)
for (tx = tilex; tx <= tilew; tx++)
image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty);
ibuf->userflags |= IB_BITMAPDIRTY;

View File

@ -133,6 +133,8 @@ typedef struct ImagePaintState {
char *warnpackedfile;
char *warnmultifile;
bool do_masking;
/* viewport texture paint only, but _not_ project paint */
Object *ob;
int faceindex;
@ -327,7 +329,7 @@ static void brush_painter_2d_tiled_tex_partial_update(BrushPainter *painter, con
brush_painter_2d_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos);
}
static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float pos[2], int use_color_correction)
static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float pos[2], bool use_color_correction, bool use_brush_alpha)
{
const Scene *scene = painter->scene;
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@ -347,7 +349,7 @@ static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float po
}
if (diameter != cache->lastsize ||
alpha != cache->lastalpha ||
(use_brush_alpha && alpha != cache->lastalpha) ||
brush->jitter != cache->lastjitter ||
rotation != cache->last_rotation ||
do_random)
@ -365,11 +367,13 @@ static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float po
size = (cache->size) ? cache->size : diameter;
if (do_tiled) {
BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf, use_color_correction);
BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf,
use_color_correction, use_brush_alpha);
brush_painter_2d_tiled_tex_partial_update(painter, pos);
}
else
BKE_brush_imbuf_new(scene, brush, flt, 2, size, &cache->ibuf, use_color_correction);
BKE_brush_imbuf_new(scene, brush, flt, 2, size, &cache->ibuf,
use_color_correction, use_brush_alpha);
cache->lastsize = diameter;
cache->lastalpha = alpha;
@ -552,7 +556,8 @@ static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos)
tot = paint_2d_torus_split_region(region, ibufb, ibuf);
for (a = 0; a < tot; a++)
IMB_rectblend(ibufb, ibuf, region[a].destx, region[a].desty,
IMB_rectblend(ibufb, ibufb, ibuf, NULL, 0, region[a].destx, region[a].desty,
region[a].destx, region[a].desty,
region[a].srcx, region[a].srcy,
region[a].width, region[a].height, IMB_BLEND_COPY_RGB);
}
@ -565,9 +570,9 @@ static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
IMB_rectblend(clonebuf, ibuf, destx, desty, srcx, srcy, w, h,
IMB_rectblend(clonebuf, clonebuf, ibuf, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h,
IMB_BLEND_COPY_RGB);
IMB_rectblend(clonebuf, ibufb, destx, desty, destx, desty, w, h,
IMB_rectblend(clonebuf, clonebuf, ibufb, NULL, 0, destx, desty, destx, desty, destx, desty, w, h,
IMB_BLEND_COPY_ALPHA);
return clonebuf;
@ -582,12 +587,14 @@ static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[
static int paint_2d_op(void *state, ImBuf *ibufb, const float lastpos[2], const float pos[2])
{
ImagePaintState *s = ((ImagePaintState *)state);
ImBuf *clonebuf = NULL, *frombuf;
ImBuf *clonebuf = NULL, *frombuf, *tmpbuf = NULL;
ImagePaintRegion region[4];
short torus = s->brush->flag & BRUSH_TORUS;
short blend = s->blend;
float *offset = s->brush->clone.offset;
float liftpos[2];
float brush_alpha = BKE_brush_alpha_get(s->scene, s->brush);
unsigned short mask_max = (unsigned short)(brush_alpha * 65535.0f);
int bpos[2], blastpos[2], bliftpos[2];
int a, tot;
@ -623,19 +630,55 @@ static int paint_2d_op(void *state, ImBuf *ibufb, const float lastpos[2], const
tot = 1;
}
if (s->do_masking)
tmpbuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
/* blend into canvas */
for (a = 0; a < tot; a++) {
imapaint_dirty_region(s->image, s->canvas,
region[a].destx, region[a].desty,
region[a].width, region[a].height);
if (s->do_masking) {
/* masking, find original pixels tiles from undo buffer to composite over */
int tilex, tiley, tilew, tileh, tx, ty;
IMB_rectblend(s->canvas, frombuf,
region[a].destx, region[a].desty,
region[a].srcx, region[a].srcy,
region[a].width, region[a].height, blend);
imapaint_region_tiles(s->canvas, region[a].destx, region[a].desty,
region[a].width, region[a].height,
&tilex, &tiley, &tilew, &tileh);
for (ty = tiley; ty <= tileh; ty++) {
for (tx = tilex; tx <= tilew; tx++) {
/* retrieve original pixels + mask from undo buffer */
unsigned short *mask;
int origx = region[a].destx - tx * IMAPAINT_TILE_SIZE;
int origy = region[a].desty - ty * IMAPAINT_TILE_SIZE;
if (s->canvas->rect_float)
tmpbuf->rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask);
else
tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask);
IMB_rectblend(s->canvas, tmpbuf, frombuf, mask, mask_max,
region[a].destx, region[a].desty,
origx, origy,
region[a].srcx, region[a].srcy,
region[a].width, region[a].height, blend);
}
}
}
else {
/* no masking, composite brush directly onto canvas */
IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, 0,
region[a].destx, region[a].desty,
region[a].destx, region[a].desty,
region[a].srcx, region[a].srcy,
region[a].width, region[a].height, blend);
}
}
if (clonebuf) IMB_freeImBuf(clonebuf);
if (tmpbuf) IMB_freeImBuf(tmpbuf);
return 1;
}
@ -684,6 +727,11 @@ static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
IMB_rect_from_float(s->clonecanvas);
}
/* set masking */
s->do_masking = (s->brush->flag & BRUSH_AIRBRUSH || (s->brush->mtex.tex &&
!ELEM(s->brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL)))
? false : true;
return 1;
}
@ -691,6 +739,9 @@ static void paint_2d_canvas_free(ImagePaintState *s)
{
BKE_image_release_ibuf(s->image, s->canvas, NULL);
BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL);
if (s->do_masking)
image_undo_remove_masks();
}
int paint_2d_stroke(void *ps, const int prev_mval[2], const int mval[2], int eraser)
@ -734,7 +785,7 @@ int paint_2d_stroke(void *ps, const int prev_mval[2], const int mval[2], int era
*/
brush_painter_2d_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0);
brush_painter_2d_refresh_cache(painter, newuv, is_data == false);
brush_painter_2d_refresh_cache(painter, newuv, is_data == false, s->do_masking);
if (paint_2d_op(s, painter->cache.ibuf, olduv, newuv)) {
imapaint_image_update(s->sima, s->image, ibuf, false);

View File

@ -3887,6 +3887,8 @@ static void *do_projectpaint_thread(void *ph_v)
mask *= BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
}
CLAMP(mask, 0.0f, 1.0f);
if (ps->do_masking) {
/* masking to keep brush contribution to a pixel limited. note we do not do
* a simple max(mask, mask_accum), as this is very sensitive to spacing and

View File

@ -126,7 +126,9 @@ typedef struct ImagePaintPartialRedraw {
#define IMAPAINT_CHAR_TO_FLOAT(c) ((c) / 255.0f)
int image_texture_paint_poll(struct bContext *C);
void *image_undo_find_tile(struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask);
void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile);
void image_undo_remove_masks(void);
void image_undo_restore(struct bContext *C, struct ListBase *lb);
void image_undo_free(struct ListBase *lb);
void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, short texpaint);
@ -134,6 +136,7 @@ struct ImagePaintPartialRedraw *get_imapaintpartial(void);
void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr);
void imapaint_clear_partial_redraw(void);
void imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h);
void imapaint_region_tiles(struct ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th);
int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy);
void *paint_2d_new_stroke(struct bContext *, struct wmOperator *);
void paint_2d_redraw(const bContext *C, void *ps, int final);

View File

@ -178,8 +178,10 @@ void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
int *desty, int *srcx, int *srcy, int *width, int *height);
void IMB_rectcpy(struct ImBuf *drect, struct ImBuf *srect, int destx,
int desty, int srcx, int srcy, int width, int height);
void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode);
void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *obuf, struct ImBuf *sbuf,
unsigned short *mask, unsigned short mask_max,
int destx, int desty, int origx, int origy, int srcx, int srcy,
int width, int height, IMB_BlendMode mode);
/**
*

View File

@ -104,7 +104,7 @@ void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_Blend
/* clipping */
void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
void IMB_rectclip(ImBuf *dbuf, ImBuf *sbuf, int *destx,
int *desty, int *srcx, int *srcy, int *width, int *height)
{
int tmp;
@ -150,43 +150,125 @@ void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
}
}
static void imb_rectclip3(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, int *destx,
int *desty, int *origx, int *origy, int *srcx, int *srcy,
int *width, int *height)
{
int tmp;
if (dbuf == NULL) return;
if (*destx < 0) {
*srcx -= *destx;
*origx -= *destx;
*width += *destx;
*destx = 0;
}
if (*origx < 0) {
*destx -= *origx;
*srcx -= *origx;
*width += *origx;
*origx = 0;
}
if (*srcx < 0) {
*destx -= *srcx;
*origx -= *srcx;
*width += *srcx;
*srcx = 0;
}
if (*desty < 0) {
*srcy -= *desty;
*origy -= *desty;
*height += *desty;
*desty = 0;
}
if (*origy < 0) {
*desty -= *origy;
*srcy -= *origy;
*height += *origy;
*origy = 0;
}
if (*srcy < 0) {
*desty -= *srcy;
*origy -= *srcy;
*height += *srcy;
*srcy = 0;
}
tmp = dbuf->x - *destx;
if (*width > tmp) *width = tmp;
tmp = dbuf->y - *desty;
if (*height > tmp) *height = tmp;
if (obuf) {
tmp = obuf->x - *origx;
if (*width > tmp) *width = tmp;
tmp = obuf->y - *origy;
if (*height > tmp) *height = tmp;
}
if (sbuf) {
tmp = sbuf->x - *srcx;
if (*width > tmp) *width = tmp;
tmp = sbuf->y - *srcy;
if (*height > tmp) *height = tmp;
}
if ((*height <= 0) || (*width <= 0)) {
*width = 0;
*height = 0;
}
}
/* copy and blend */
void IMB_rectcpy(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
void IMB_rectcpy(ImBuf *dbuf, ImBuf *sbuf, int destx,
int desty, int srcx, int srcy, int width, int height)
{
IMB_rectblend(dbuf, sbuf, destx, desty, srcx, srcy, width, height,
IMB_BLEND_COPY);
IMB_rectblend(dbuf, dbuf, sbuf, NULL, 0, destx, desty, destx, desty, srcx, srcy, width, height, IMB_BLEND_COPY);
}
typedef void (*IMB_blend_func)(unsigned char *dst, const unsigned char *src1, const unsigned char *src2);
typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2);
void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode)
void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *maskrect, unsigned short mask_max,
int destx, int desty, int origx, int origy, 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;
unsigned int *drect = NULL, *orect, *srect = NULL, *dr, *or, *sr;
float *drectf = NULL, *orectf, *srectf = NULL, *drf, *orf, *srf;
unsigned short *mr;
int do_float, do_char, srcskip, destskip, origskip, x;
IMB_blend_func func = NULL;
IMB_blend_func_float func_float = NULL;
if (dbuf == NULL) return;
if (dbuf == NULL || obuf == NULL) return;
IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &width, &height);
imb_rectclip3(dbuf, obuf, sbuf, &destx, &desty, &origx, &origy, &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;
do_char = (sbuf && sbuf->rect && dbuf->rect && obuf->rect);
do_float = (sbuf && sbuf->rect_float && dbuf->rect_float && obuf->rect_float);
if (do_char) {
drect = dbuf->rect + desty * dbuf->x + destx;
orect = obuf->rect + origy * obuf->x + origx;
}
if (do_float) {
drectf = dbuf->rect_float + (desty * dbuf->x + destx) * 4;
orectf = obuf->rect_float + (origy * obuf->x + origx) * 4;
}
if (maskrect)
maskrect += origy * obuf->x + origx;
destskip = dbuf->x;
origskip = obuf->x;
if (sbuf) {
if (do_char) srect = sbuf->rect + srcy * sbuf->x + srcx;
@ -307,24 +389,92 @@ void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
for (; height > 0; height--) {
if (do_char) {
dr = drect;
or = orect;
sr = srect;
for (x = width; x > 0; x--, dr++, sr++) {
if (((unsigned char *)sr)[3])
func((unsigned char *)dr, (unsigned char *)dr, (unsigned char *)sr);
if (maskrect) {
/* mask accumulation for painting */
mr = maskrect;
for (x = width; x > 0; x--, dr++, or++, sr++, mr++) {
unsigned char *src = (unsigned char*)sr;
if (src[3]) {
unsigned short mask = *mr + divide_round_i((mask_max - *mr) * src[3], 255);
if (mask > *mr) {
unsigned char mask_src[4];
*mr = mask;
mask_src[0] = src[0];
mask_src[1] = src[1];
mask_src[2] = src[2];
mask_src[3] = mask >> 8;
func((unsigned char *)dr, (unsigned char *)or, mask_src);
}
}
}
maskrect += origskip;
}
else {
/* regular blending */
for (x = width; x > 0; x--, dr++, or++, sr++) {
if (((unsigned char *)sr)[3])
func((unsigned char *)dr, (unsigned char *)or, (unsigned char *)sr);
}
}
drect += destskip;
orect += origskip;
srect += srcskip;
}
if (do_float) {
drf = drectf;
orf = orectf;
srf = srectf;
for (x = width; x > 0; x--, drf += 4, srf += 4) {
if (srf[3] != 0)
func_float(drf, drf, srf);
if (maskrect) {
/* mask accumulation for painting */
mr = maskrect;
for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, mr++) {
if (srf[3] != 0) {
float alpha = CLAMPIS(srf[3], 0.0f, 1.0f);
unsigned short mask = (unsigned short)(*mr + (mask_max - *mr) * alpha);
if (mask > *mr) {
float mask_srf[4];
float new_alpha = mask * (1.0f/65535.0f);
float map_alpha = new_alpha / srf[3];
*mr = mask;
mask_srf[0] = map_alpha * srf[0];
mask_srf[1] = map_alpha * srf[1];
mask_srf[2] = map_alpha * srf[2];
mask_srf[3] = new_alpha;
func_float(drf, orf, mask_srf);
}
}
}
maskrect += origskip;
}
else {
/* regular blending */
for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4) {
if (srf[3] != 0)
func_float(drf, orf, srf);
}
}
drectf += destskip * 4;
orectf += origskip * 4;
srectf += srcskip * 4;
}
}
@ -333,7 +483,7 @@ void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
/* fill */
void IMB_rectfill(struct ImBuf *drect, const float col[4])
void IMB_rectfill(ImBuf *drect, const float col[4])
{
int num;
@ -462,7 +612,7 @@ void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height,
}
}
void IMB_rectfill_area(struct ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2, struct ColorManagedDisplay *display)
void IMB_rectfill_area(ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2, struct ColorManagedDisplay *display)
{
if (!ibuf) return;
buf_rectfill_area((unsigned char *) ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, col, display,

View File

@ -163,7 +163,7 @@ void ImageBuff::plot(unsigned char *img, short width, short height, short x, sho
// assign temporarily our buffer to the ImBuf buffer, we use the same format
tmpbuf->rect = (unsigned int*)img;
m_imbuf->rect = m_image;
IMB_rectblend(m_imbuf, tmpbuf, x, y, 0, 0, width, height, (IMB_BlendMode)mode);
IMB_rectblend(m_imbuf, m_imbuf, tmpbuf, NULL, 0, x, y, x, y, 0, 0, width, height, (IMB_BlendMode)mode);
// remove so that MB_freeImBuf will free our buffer
m_imbuf->rect = NULL;
tmpbuf->rect = NULL;
@ -186,7 +186,7 @@ void ImageBuff::plot(ImageBuff *img, short x, short y, short mode)
// assign temporarily our buffer to the ImBuf buffer, we use the same format
img->m_imbuf->rect = img->m_image;
m_imbuf->rect = m_image;
IMB_rectblend(m_imbuf, img->m_imbuf, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode);
IMB_rectblend(m_imbuf, m_imbuf, img->m_imbuf, NULL, 0, x, y, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode);
// remove so that MB_freeImBuf will free our buffer
m_imbuf->rect = NULL;
img->m_imbuf->rect = NULL;