From e168d67b3205977777715f143554a15f259c0a40 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 31 Jul 2006 15:53:03 +0000 Subject: ImagePaint Refactoring: - ImagePaint now uses ImBuf directly, and the rect blending functions were moved into the imbuf module. - The brush spacing, timing and sampling was abstracted into brush.c, for later reuse in other paint modes. Float ImagePaint support. Textured Brushes: - Only the first texture channel is used now. - Options for size and offset should be added, but need to find some space in the panel, or add a second one .. --- source/blender/blenkernel/BKE_brush.h | 27 +- .../blenkernel/bad_level_call_stubs/stubs.c | 2 +- source/blender/blenkernel/intern/brush.c | 478 ++++++++++--- source/blender/blenkernel/intern/texture.c | 27 +- source/blender/blenloader/intern/readfile.c | 25 +- source/blender/blenloader/intern/writefile.c | 10 +- source/blender/imbuf/IMB_imbuf.h | 25 + source/blender/imbuf/intern/rectop.c | 481 +++++++++++-- source/blender/include/blendef.h | 2 + source/blender/include/butspace.h | 1 + source/blender/makesdna/DNA_brush_types.h | 10 + .../blender/render/extern/include/RE_render_ext.h | 4 +- source/blender/render/intern/source/texture.c | 4 +- source/blender/src/buttons_editing.c | 17 + source/blender/src/buttons_shading.c | 30 +- source/blender/src/drawimage.c | 37 + source/blender/src/header_buttonswin.c | 8 + source/blender/src/headerbuttons.c | 53 +- source/blender/src/imagepaint.c | 779 ++++++--------------- 19 files changed, 1256 insertions(+), 764 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 89c6a3adf2a..a55c8913c7f 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -36,22 +36,37 @@ struct ID; struct Brush; +struct ImBuf; +/* datablock functions */ struct Brush *add_brush(char *name); struct Brush *copy_brush(struct Brush *brush); void make_local_brush(struct Brush *brush); void free_brush(struct Brush *brush); -/* implementation of blending modes for use by different paint modes */ -void brush_blend_rgb(char *outcol, char *col1, char *col2, int fac, short mode); - -/* functions for brush datablock browsing used by different paint panels */ +/* brush library operations used by different paint panels */ int brush_set_nr(struct Brush **current_brush, int nr); int brush_delete(struct Brush **current_brush); +void brush_check_exists(struct Brush **brush); void brush_toggle_fake_user(struct Brush *brush); -int brush_clone_image_delete(struct Brush *brush); +int brush_texture_set_nr(struct Brush *brush, int nr); +int brush_texture_delete(struct Brush *brush); int brush_clone_image_set_nr(struct Brush *brush, int nr); -void brush_check_exists(struct Brush **brush); +int brush_clone_image_delete(struct Brush *brush); + +/* sampling */ +void brush_sample(struct Brush *brush, float *xy, float dist, float *rgb, float *alpha, short texonly); +struct ImBuf *brush_imbuf_new(struct Brush *brush, short flt, short texonly, int size); + +/* painting */ +struct BrushPainter; +typedef struct BrushPainter BrushPainter; +typedef int (*BrushFunc)(void *user, struct ImBuf *ibuf, float *lastpos, float *pos); + +BrushPainter *brush_painter_new(struct Brush *brush); +void brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size); +int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, void *user); +void brush_painter_free(BrushPainter *painter); #endif diff --git a/source/blender/blenkernel/bad_level_call_stubs/stubs.c b/source/blender/blenkernel/bad_level_call_stubs/stubs.c index 1bad2de5bbc..97c0d4c7ff7 100644 --- a/source/blender/blenkernel/bad_level_call_stubs/stubs.c +++ b/source/blender/blenkernel/bad_level_call_stubs/stubs.c @@ -228,7 +228,7 @@ void fluidsimSettingsFree(struct FluidsimSettings* sb) {} void fluidsimSettingsCopy(struct FluidsimSettings* sb) {} /*new render funcs */ -void externtex(struct MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta) {} +int externtex(struct MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta) { return 0; } int multitex(struct Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, struct TexResult *texres) {return 0;} struct Render *RE_GetRender(const char *name) {return (struct Render *)NULL;} struct RenderResult *RE_GetResult(Render *re) {return (struct RenderResult *)NULL;} diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 383cf5b3fe8..61d0b42d30d 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -30,18 +30,31 @@ * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ +#include + #include "MEM_guardedalloc.h" #include "DNA_brush_types.h" #include "DNA_image_types.h" +#include "DNA_texture_types.h" #include "DNA_scene_types.h" +#include "BLI_arithb.h" #include "BLI_blenlib.h" #include "BKE_brush.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "RE_render_ext.h" /* externtex */ + +/* Datablock add/copy/free/make_local */ Brush *add_brush(char *name) { @@ -68,9 +81,19 @@ Brush *add_brush(char *name) Brush *copy_brush(Brush *brush) { Brush *brushn; + MTex *mtex; + int a; brushn= copy_libblock(brush); + for(a=0; amtex[a]; + if(mtex) { + brushn->mtex[a]= MEM_dupallocN(mtex); + if(mtex->tex) id_us_plus((ID*)mtex->tex); + } + } + /* enable fake user by default */ if (!(brushn->id.flag & LIB_FAKEUSER)) brush_toggle_fake_user(brushn); @@ -81,16 +104,24 @@ Brush *copy_brush(Brush *brush) /* not brush itself */ void free_brush(Brush *brush) { + MTex *mtex; + int a; + + for(a=0; amtex[a]; + if(mtex) { + if(mtex->tex) mtex->tex->id.us--; + MEM_freeN(mtex); + } + } } void make_local_brush(Brush *brush) { - /* don't forget: add stuff texture make local once texture bruses are added*/ - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ + * - only local users: set flag + * - mixed: make copy + */ Brush *brushn; Scene *scene; @@ -99,11 +130,11 @@ void make_local_brush(Brush *brush) if(brush->id.lib==0) return; if(brush->clone.image) { - /* special case: ima always local immediately */ + /* special case: ima always local immediately */ brush->clone.image->id.lib= 0; brush->clone.image->id.flag= LIB_LOCAL; new_id(0, (ID *)brush->clone.image, 0); - } + } for(scene= G.main->scene.first; scene; scene=scene->id.next) if(scene->toolsettings->imapaint.brush==brush) { @@ -135,103 +166,7 @@ void make_local_brush(Brush *brush) } } -static void brush_blend_mix(char *cp, char *cp1, char *cp2, int fac) -{ - /* this and other blending modes previously used >>8 instead of /255. both - are not equivalent (>>8 is /256), and the former results in rounding - errors that can turn colors black fast */ - int mfac= 255-fac; - cp[0]= (mfac*cp1[0]+fac*cp2[0])/255; - cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; - cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; -} - -static void brush_blend_add(char *cp, char *cp1, char *cp2, int fac) -{ - int temp; - - temp= cp1[0] + ((fac*cp2[0])/255); - if(temp>254) cp[0]= 255; else cp[0]= temp; - temp= cp1[1] + ((fac*cp2[1])/255); - if(temp>254) cp[1]= 255; else cp[1]= temp; - temp= cp1[2] + ((fac*cp2[2])/255); - if(temp>254) cp[2]= 255; else cp[2]= temp; -} - -static void brush_blend_sub(char *cp, char *cp1, char *cp2, int fac) -{ - int temp; - - temp= cp1[0] - ((fac*cp2[0])/255); - if(temp<0) cp[0]= 0; else cp[0]= temp; - temp= cp1[1] - ((fac*cp2[1])/255); - if(temp<0) cp[1]= 0; else cp[1]= temp; - temp= cp1[2] - ((fac*cp2[2])/255); - if(temp<0) cp[2]= 0; else cp[2]= temp; -} - -static void brush_blend_mul(char *cp, char *cp1, char *cp2, int fac) -{ - int mfac= 255-fac; - - /* first mul, then blend the fac */ - cp[0]= (mfac*cp1[0] + fac*((cp2[0]*cp1[0])/255))/255; - cp[1]= (mfac*cp1[1] + fac*((cp2[1]*cp1[1])/255))/255; - cp[2]= (mfac*cp1[2] + fac*((cp2[2]*cp1[2])/255))/255; -} - -static void brush_blend_lighten(char *cp, char *cp1, char *cp2, int fac) -{ - /* See if are lighter, if so mix, else dont do anything. - if the paint col is darker then the original, then ignore */ - if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) { - cp[0]= cp1[0]; - cp[1]= cp1[1]; - cp[2]= cp1[2]; - } - else - brush_blend_mix(cp, cp1, cp2, fac); -} - -static void brush_blend_darken(char *cp, char *cp1, char *cp2, int fac) -{ - /* See if were darker, if so mix, else dont do anything. - if the paint col is brighter then the original, then ignore */ - if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) { - cp[0]= cp1[0]; - cp[1]= cp1[1]; - cp[2]= cp1[2]; - } - else - brush_blend_mix(cp, cp1, cp2, fac); -} - -void brush_blend_rgb(char *outcol, char *col1, char *col2, int fac, short mode) -{ - if (fac==0) { - outcol[0]= col1[0]; - outcol[1]= col1[1]; - outcol[2]= col1[2]; - } - else { - switch (mode) { - case BRUSH_BLEND_MIX: - brush_blend_mix(outcol, col1, col2, fac); break; - case BRUSH_BLEND_ADD: - brush_blend_add(outcol, col1, col2, fac); break; - case BRUSH_BLEND_SUB: - brush_blend_sub(outcol, col1, col2, fac); break; - case BRUSH_BLEND_MUL: - brush_blend_mul(outcol, col1, col2, fac); break; - case BRUSH_BLEND_LIGHTEN: - brush_blend_lighten(outcol, col1, col2, fac); break; - case BRUSH_BLEND_DARKEN: - brush_blend_darken(outcol, col1, col2, fac); break; - default: - brush_blend_mix(outcol, col1, col2, fac); break; - } - } -} +/* Library Operations */ int brush_set_nr(Brush **current_brush, int nr) { @@ -261,6 +196,7 @@ int brush_delete(Brush **current_brush) if (*current_brush) { (*current_brush)->id.us--; *current_brush= NULL; + return 1; } @@ -281,6 +217,51 @@ void brush_toggle_fake_user(Brush *brush) } } +int brush_texture_set_nr(Brush *brush, int nr) +{ + ID *idtest, *id=NULL; + + if(brush->mtex[brush->texact]) + id= (ID *)brush->mtex[brush->texact]->tex; + + idtest= (ID*)BLI_findlink(&G.main->tex, nr-1); + if(idtest==0) { /* new tex */ + if(id) idtest= (ID *)copy_texture((Tex *)id); + else idtest= (ID *)add_texture("Tex"); + idtest->us--; + } + if(idtest!=id) { + brush_texture_delete(brush); + + if(brush->mtex[brush->texact]==NULL) { + brush->mtex[brush->texact]= add_mtex(); + brush->mtex[brush->texact]->r = 1.0f; + brush->mtex[brush->texact]->g = 1.0f; + brush->mtex[brush->texact]->b = 1.0f; + } + brush->mtex[brush->texact]->tex= (Tex*)idtest; + id_us_plus(idtest); + + return 1; + } + + return 0; +} + +int brush_texture_delete(Brush *brush) +{ + if(brush->mtex[brush->texact]) { + if(brush->mtex[brush->texact]->tex) + brush->mtex[brush->texact]->tex->id.us--; + MEM_freeN(brush->mtex[brush->texact]); + brush->mtex[brush->texact]= NULL; + + return 1; + } + + return 0; +} + int brush_clone_image_set_nr(Brush *brush, int nr) { if(brush && nr > 0) { @@ -316,3 +297,292 @@ void brush_check_exists(Brush **brush) brush_set_nr(brush, 1); } +/* Brush Sampling */ + +static float brush_sample_falloff(Brush *brush, float dist) +{ + float a, outer, inner; + + outer = brush->size >> 1; + inner = outer*brush->innerradius; + + if (dist <= inner) { + return brush->alpha; + } + else if ((dist < outer) && (inner < outer)) { + /* formula used by sculpt: + 0.5f * (cos(3*(dist - inner)/(outer - inner)) + 1); */ + a = sqrt((dist - inner)/(outer - inner)); + return (1 - a)*brush->alpha; + } + else + return 0.0f; +} + +void brush_sample(Brush *brush, float *xy, float dist, float *rgb, float *alpha, short texonly) +{ + if (alpha) { + if (texonly) *alpha= 1.0; + else *alpha= brush_sample_falloff(brush, dist); + } + + if (xy && brush->mtex[0] && brush->mtex[0]->tex) { + float co[3], tin, tr, tg, tb, ta; + int hasrgb; + + co[0]= xy[0]/(brush->size >> 1); + co[1]= xy[1]/(brush->size >> 1); + co[2]= 0.0f; + + hasrgb= externtex(brush->mtex[0], co, &tin, &tr, &tg, &tb, &ta); + + if (rgb) { + if (hasrgb) { + rgb[0]= tr*brush->rgb[0]; + rgb[1]= tg*brush->rgb[1]; + rgb[2]= tb*brush->rgb[2]; + } + else { + rgb[0]= tin*brush->rgb[0]; + rgb[1]= tin*brush->rgb[1]; + rgb[2]= tin*brush->rgb[2]; + } + } + if (alpha && hasrgb) + *alpha *= ta; + } + else if (rgb) + VECCOPY(rgb, brush->rgb) +} + +#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val)) + +ImBuf *brush_imbuf_new(Brush *brush, short flt, short texonly, int size) +{ + ImBuf *ibuf; + float w_2, h_2, xy[2], dist, rgba[3], *dstf; + unsigned int x, y, rowbytes; + char *dst; + + if (texonly && !(brush->mtex[0] && brush->mtex[0]->tex)) + return NULL; + + w_2 = size/2.0f; + h_2 = size/2.0f; + rowbytes= size*4; + + if (flt) { + ibuf= IMB_allocImBuf(size, size, 32, IB_rectfloat, 0); + + 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 + 0.5f - w_2; + xy[1] = y + 0.5f - h_2; + dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); + + brush_sample(brush, xy, dist, dstf, dstf+3, texonly); + } + } + } + else { + ibuf= IMB_allocImBuf(size, size, 32, IB_rect, 0); + + for (y=0; y < ibuf->y; y++) { + dst = (char*)ibuf->rect + y*rowbytes; + + for (x=0; x < ibuf->x; x++, dst+=4) { + xy[0] = x + 0.5f - w_2; + xy[1] = y + 0.5f - h_2; + dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); + + brush_sample(brush, xy, dist, rgba, rgba+3, texonly); + dst[0]= FTOCHAR(rgba[0]); + dst[1]= FTOCHAR(rgba[1]); + dst[2]= FTOCHAR(rgba[2]); + dst[3]= FTOCHAR(rgba[3]); + } + } + } + + return ibuf; +} + +/* Brush Painting */ + +struct BrushPainter { + Brush *brush; + + float lastmousepos[2]; /* mouse position of last paint call */ + + float accumdistance; /* accumulated distance of brush since last paint op */ + float lastpaintpos[2]; /* position of last paint op */ + + double accumtime; /* accumulated time since last paint op (airbrush) */ + double lasttime; /* time of last update */ + + short firsttouch; /* first paint op */ + + struct BrushPainterImbufCache { + int size; /* size override, if 0 uses brush->size */ + short flt; /* need float imbuf? */ + short texonly; /* no alpha, color or fallof, only texture in imbuf */ + short enabled; + + int lastsize; + float lastalpha; + float lastinnerradius; + + ImBuf *ibuf; + } cache; +}; + +BrushPainter *brush_painter_new(Brush *brush) +{ + BrushPainter *painter= MEM_callocN(sizeof(BrushPainter), "BrushPainter"); + + painter->brush= brush; + painter->firsttouch= 1; + + return painter; +} + +void brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size) +{ + painter->cache.size = size; + painter->cache.flt = flt; + painter->cache.texonly = texonly; + painter->cache.enabled = 1; +} + +void brush_painter_free(BrushPainter *painter) +{ + if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); + MEM_freeN(painter); +} + +static void brush_painter_refresh_cache(BrushPainter *painter) +{ + Brush *brush= painter->brush; + + if ((brush->size != painter->cache.lastsize) + || (brush->alpha != painter->cache.lastalpha) + || (brush->innerradius != painter->cache.lastinnerradius)) { + + if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); + + painter->cache.ibuf= brush_imbuf_new(brush, + painter->cache.flt, painter->cache.texonly, + painter->cache.size? painter->cache.size: brush->size); + + painter->cache.lastsize= brush->size; + painter->cache.lastalpha= brush->alpha; + painter->cache.lastinnerradius= brush->innerradius; + } +} + +int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, void *user) +{ + Brush *brush= painter->brush; + int totpaintops= 0; + + if (painter->firsttouch) { + /* paint exactly once on first touch */ + if (painter->cache.enabled) brush_painter_refresh_cache(painter); + totpaintops += func(user, painter->cache.ibuf, pos, pos); + + painter->lastpaintpos[0]= pos[0]; + painter->lastpaintpos[1]= pos[1]; + painter->lasttime= time; + + painter->firsttouch= 0; + } +#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; //brush->size*brush->spacing*0.01f; + + /* setup starting time, direction vector and accumulated time */ + starttime= painter->accumtime; + Vec2Subf(dmousepos, pos, painter->lastmousepos); + len= Normalise2(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]; + + /* compute brush spacing adapted to brush size */ + spacing= brush->size*brush->spacing*0.01f; + + /* setup starting distance, direction vector and accumulated distance */ + startdistance= painter->accumdistance; + Vec2Subf(dmousepos, pos, painter->lastmousepos); + painter->accumdistance += Normalise2(dmousepos); + + /* do paint op over unpainted distance */ + while (painter->accumdistance >= spacing) { + step= spacing - startdistance; + 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->accumdistance -= spacing; + startdistance -= spacing; + } + + /* 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 >= brush->rate) { + if (painter->cache.enabled) brush_painter_refresh_cache(painter); + totpaintops += func(user, painter->cache.ibuf, painter->lastmousepos, pos); + painter->accumtime -= brush->rate; + } + + painter->lasttime= curtime; + } + } + + painter->lastmousepos[0]= pos[0]; + painter->lastmousepos[1]= pos[1]; + + return totpaintops; +} + + diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index aa36c0a5083..3f78ad3a1d6 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -58,6 +58,7 @@ #include "DNA_material_types.h" #include "DNA_image_types.h" #include "DNA_world_types.h" +#include "DNA_brush_types.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -77,6 +78,7 @@ #include "BKE_key.h" #include "BKE_icons.h" #include "BKE_ipo.h" +#include "BKE_brush.h" /* ------------------------------------------------------------------------- */ @@ -545,6 +547,7 @@ void make_local_texture(Tex *tex) Material *ma; World *wrld; Lamp *la; + Brush *br; int a, local=0, lib=0; /* - only lib users: do nothing @@ -599,6 +602,16 @@ void make_local_texture(Tex *tex) } wrld= wrld->id.next; } + br= G.main->brush.first; + while(br) { + for(a=0; amtex[a] && br->mtex[a]->tex==tex) { + if(br->id.lib) lib= 1; + else local= 1; + } + } + br= br->id.next; + } if(local && lib==0) { tex->id.lib= 0; @@ -648,7 +661,19 @@ void make_local_texture(Tex *tex) } wrld= wrld->id.next; } - + br= G.main->brush.first; + while(br) { + for(a=0; amtex[a] && br->mtex[a]->tex==tex) { + if(br->id.lib==0) { + br->mtex[a]->tex= texn; + texn->id.us++; + tex->id.us--; + } + } + } + br= br->id.next; + } } } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 17bf34f6f45..fa6fe7bb3b0 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1183,26 +1183,36 @@ static void test_pointer_array(FileData *fd, void **mat) } } -/* ************ READ BRUSH *************** */ +/* ************ READ Brush *************** */ /* library brush linking after fileread */ static void lib_link_brush(FileData *fd, Main *main) { Brush *brush; + MTex *mtex; + int a; /* only link ID pointers */ for(brush= main->brush.first; brush; brush= brush->id.next) { if(brush->id.flag & LIB_NEEDLINK) { brush->id.flag -= LIB_NEEDLINK; - /* nothing to do yet - until brush gets textures */ + + for(a=0; amtex[a]; + if(mtex) + mtex->tex= newlibadr_us(fd, brush->id.lib, mtex->tex); + } } } } -/* brush itself has been read! */ static void direct_link_brush(FileData *fd, Brush *brush) { - /* nothing to do yet - until brush gets textures */ + /* brush itself has been read */ + int a; + + for(a=0; amtex[a]= newdataadr(fd, brush->mtex[a]); } /* ************ READ CurveMapping *************** */ @@ -5802,7 +5812,12 @@ static void expand_texture(FileData *fd, Main *mainvar, Tex *tex) static void expand_brush(FileData *fd, Main *mainvar, Brush *brush) { - /* nothing to do yet - until brush gets texture */ + int a; + + for(a=0; amtex[a]) + expand_doit(fd, mainvar, brush->mtex[a]->tex); + expand_doit(fd, mainvar, brush->clone.image); } static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree) diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index e3a67da94c3..7c0e81169f7 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1596,10 +1596,16 @@ static void write_nodetrees(WriteData *wd, ListBase *idbase) static void write_brushes(WriteData *wd, ListBase *idbase) { Brush *brush; + int a; - for(brush=idbase->first; brush; brush= brush->id.next) - if (brush->id.us>0 || wd->current) + for(brush=idbase->first; brush; brush= brush->id.next) { + if(brush->id.us>0 || wd->current) { writestruct(wd, ID_BR, "Brush", 1, brush); + for(a=0; amtex[a]) + writestruct(wd, DATA, "MTex", 1, brush->mtex[a]); + } + } } static void write_global(WriteData *wd) diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index c55e353ee6c..5eaac146c4e 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -219,8 +219,33 @@ void IMB_freecmapImBuf(struct ImBuf * ibuf); * * @attention Defined in rectop.c */ + +typedef enum IMB_BlendMode { + IMB_BLEND_MIX = 0, + IMB_BLEND_ADD = 1, + IMB_BLEND_SUB = 2, + IMB_BLEND_MUL = 3, + IMB_BLEND_LIGHTEN = 4, + IMB_BLEND_DARKEN = 5, + + IMB_BLEND_COPY = 1000, + IMB_BLEND_COPY_RGB = 1001, + IMB_BLEND_COPY_ALPHA = 1002 +} IMB_BlendMode; + +unsigned int IMB_blend_color(unsigned int src1, unsigned int src2, int fac, + IMB_BlendMode mode); +void IMB_blend_color_float(float *dst, float *src1, float *src2, float fac, + IMB_BlendMode mode); + +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_torus(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, + int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode); /** * Return the length (in frames) of the given @a anim. diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c index 1b806b8fa1f..59fcd3e25e2 100644 --- a/source/blender/imbuf/intern/rectop.c +++ b/source/blender/imbuf/intern/rectop.c @@ -41,104 +41,433 @@ #include "IMB_allocimbuf.h" +/* blend modes */ + +static void blend_color_mix(char *cp, char *cp1, char *cp2, int fac) +{ + /* this and other blending modes previously used >>8 instead of /255. both + are not equivalent (>>8 is /256), and the former results in rounding + errors that can turn colors black fast after repeated blending */ + int mfac= 255-fac; + cp[0]= (mfac*cp1[0]+fac*cp2[0])/255; + cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; + cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; +} + +static void blend_color_add(char *cp, char *cp1, char *cp2, int fac) +{ + int temp; + + temp= cp1[0] + ((fac*cp2[0])/255); + if(temp>254) cp[0]= 255; else cp[0]= temp; + temp= cp1[1] + ((fac*cp2[1])/255); + if(temp>254) cp[1]= 255; else cp[1]= temp; + temp= cp1[2] + ((fac*cp2[2])/255); + if(temp>254) cp[2]= 255; else cp[2]= temp; +} + +static void blend_color_sub(char *cp, char *cp1, char *cp2, int fac) +{ + int temp; + + temp= cp1[0] - ((fac*cp2[0])/255); + if(temp<0) cp[0]= 0; else cp[0]= temp; + temp= cp1[1] - ((fac*cp2[1])/255); + if(temp<0) cp[1]= 0; else cp[1]= temp; + temp= cp1[2] - ((fac*cp2[2])/255); + if(temp<0) cp[2]= 0; else cp[2]= temp; +} + +static void blend_color_mul(char *cp, char *cp1, char *cp2, int fac) +{ + int mfac= 255-fac; + + /* first mul, then blend the fac */ + cp[0]= (mfac*cp1[0] + fac*((cp1[0]*cp2[0])/255))/255; + cp[1]= (mfac*cp1[1] + fac*((cp1[1]*cp2[1])/255))/255; + cp[2]= (mfac*cp1[2] + fac*((cp1[2]*cp2[2])/255))/255; +} + +static void blend_color_lighten(char *cp, char *cp1, char *cp2, int fac) +{ + /* See if are lighter, if so mix, else dont do anything. + if the paint col is darker then the original, then ignore */ + if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) { + cp[0]= cp1[0]; + cp[1]= cp1[1]; + cp[2]= cp1[2]; + } + else + blend_color_mix(cp, cp1, cp2, fac); +} + +static void blend_color_darken(char *cp, char *cp1, char *cp2, int fac) +{ + /* See if were darker, if so mix, else dont do anything. + if the paint col is brighter then the original, then ignore */ + if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) { + cp[0]= cp1[0]; + cp[1]= cp1[1]; + cp[2]= cp1[2]; + } + else + blend_color_mix(cp, cp1, cp2, fac); +} + +unsigned int IMB_blend_color(unsigned int src1, unsigned int src2, int fac, IMB_BlendMode mode) +{ + unsigned int dst; + char *cp, *cp1, *cp2; + + if (fac==0) + return src1; + + cp = (char*)&dst; + cp1 = (char*)&src1; + cp2 = (char*)&src2; + + switch (mode) { + case IMB_BLEND_MIX: + blend_color_mix(cp, cp1, cp2, fac); break; + case IMB_BLEND_ADD: + blend_color_add(cp, cp1, cp2, fac); break; + case IMB_BLEND_SUB: + blend_color_sub(cp, cp1, cp2, fac); break; + case IMB_BLEND_MUL: + blend_color_mul(cp, cp1, cp2, fac); break; + case IMB_BLEND_LIGHTEN: + blend_color_lighten(cp, cp1, cp2, fac); break; + case IMB_BLEND_DARKEN: + blend_color_darken(cp, cp1, cp2, fac); break; + default: + return src1; + } + + return dst; +} + +static void blend_color_mix_float(float *cp, float *cp1, float *cp2, float fac) +{ + float mfac= 1.0-fac; + cp[0]= mfac*cp1[0] + fac*cp2[0]; + cp[1]= mfac*cp1[1] + fac*cp2[1]; + cp[2]= mfac*cp1[2] + fac*cp2[2]; +} + +static void blend_color_add_float(float *cp, float *cp1, float *cp2, float fac) +{ + cp[0] = cp1[0] + fac*cp2[0]; + cp[1] = cp1[1] + fac*cp2[1]; + cp[2] = cp1[2] + fac*cp2[2]; + + if (cp[0] > 1.0f) cp[0]= 1.0f; + if (cp[1] > 1.0f) cp[1]= 1.0f; + if (cp[2] > 1.0f) cp[2]= 1.0f; +} + +static void blend_color_sub_float(float *cp, float *cp1, float *cp2, float fac) +{ + cp[0] = cp1[0] - fac*cp2[0]; + cp[1] = cp1[1] - fac*cp2[1]; + cp[2] = cp1[2] - fac*cp2[2]; + + if (cp[0] < 0.0f) cp[0]= 0.0f; + if (cp[1] < 0.0f) cp[1]= 0.0f; + if (cp[2] < 0.0f) cp[2]= 0.0f; +} + +static void blend_color_mul_float(float *cp, float *cp1, float *cp2, float fac) +{ + float mfac= 1.0-fac; + + cp[0]= mfac*cp1[0] + fac*(cp1[0]*cp2[0]); + cp[1]= mfac*cp1[1] + fac*(cp1[1]*cp2[1]); + cp[2]= mfac*cp1[2] + fac*(cp1[2]*cp2[2]); +} + +static void blend_color_lighten_float(float *cp, float *cp1, float *cp2, float fac) +{ + /* See if are lighter, if so mix, else dont do anything. + if the pafloat col is darker then the original, then ignore */ + if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) { + cp[0]= cp1[0]; + cp[1]= cp1[1]; + cp[2]= cp1[2]; + } + else + blend_color_mix_float(cp, cp1, cp2, fac); +} + +static void blend_color_darken_float(float *cp, float *cp1, float *cp2, float fac) +{ + /* See if were darker, if so mix, else dont do anything. + if the pafloat col is brighter then the original, then ignore */ + if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) { + cp[0]= cp1[0]; + cp[1]= cp1[1]; + cp[2]= cp1[2]; + } + else + blend_color_mix_float(cp, cp1, cp2, fac); +} + +void IMB_blend_color_float(float *dst, float *src1, float *src2, float fac, IMB_BlendMode mode) +{ + if (fac==0) { + dst[0]= src1[0]; + dst[1]= src1[1]; + dst[2]= src1[2]; + return; + } + + switch (mode) { + case IMB_BLEND_MIX: + blend_color_mix_float(dst, src1, src2, fac); break; + case IMB_BLEND_ADD: + blend_color_add_float(dst, src1, src2, fac); break; + case IMB_BLEND_SUB: + blend_color_sub_float(dst, src1, src2, fac); break; + case IMB_BLEND_MUL: + blend_color_mul_float(dst, src1, src2, fac); break; + case IMB_BLEND_LIGHTEN: + blend_color_lighten_float(dst, src1, src2, fac); break; + case IMB_BLEND_DARKEN: + blend_color_darken_float(dst, src1, src2, fac); break; + default: + dst[0]= src1[0]; + dst[1]= src1[1]; + dst[2]= src1[2]; + } +} + +/* clipping */ + +void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx, + int *desty, int *srcx, int *srcy, int *width, int *height) +{ + int tmp; + + if (dbuf == NULL) return; + + if (*destx < 0) { + *srcx -= *destx ; + *width += *destx ; + *destx = 0; + } + if (*srcx < 0) { + *destx -= *srcx ; + *width += *destx ; + *srcx = 0; + } + if (*desty < 0) { + *srcy -= *desty ; + *height += *desty ; + *desty = 0; + } + if (*srcy < 0) { + *desty -= *srcy ; + *height += *desty ; + *srcy = 0; + } + + tmp = dbuf->x - *destx; + if (*width > tmp) *width = tmp; + tmp = dbuf->y - *desty; + 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; + } +} + +/* copy and blend */ + void IMB_rectcpy(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, int desty, int srcx, int srcy, int width, int height) { - unsigned int *drect, *srect; - float *drectf = NULL; - float *srectf = NULL; - int tmp, do_float = 0; + IMB_rectblend(dbuf, sbuf, destx, desty, srcx, srcy, width, height, + IMB_BLEND_COPY); +} + +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->rect_float && dbuf->rect_float) do_float = 1; - - if (destx < 0){ - srcx -= destx ; - width += destx ; - destx = 0; - } - if (srcx < 0){ - destx -= srcx ; - width += destx ; - srcx = 0; - } - if (desty < 0){ - srcy -= desty ; - height += desty ; - desty = 0; - } - if (srcy < 0){ - desty -= srcy ; - height += desty ; - srcy = 0; - } - - tmp = dbuf->x - destx; - if (width > tmp) width = tmp; - tmp = dbuf->y - desty; - if (height > tmp) height = tmp; - - drect = dbuf->rect + desty * dbuf->x + destx; - if (do_float) drectf = dbuf->rect_float + desty * dbuf->x + destx; - destx = dbuf->x; - - if (sbuf){ - tmp = sbuf->x - srcx; - if (width > tmp) width = tmp; - tmp = sbuf->y - srcy; - if (height > tmp) height = tmp; - - if (width <= 0) return; - if (height <= 0) return; - - srect = sbuf->rect; - srect += srcy * sbuf->x; - srect += srcx; - if (do_float) { - srectf = sbuf->rect_float; - srectf += srcy * sbuf->x; - srectf += srcx; - } - srcx = sbuf->x; - } else{ - if (width <= 0) return; - if (height <= 0) 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; - srcx = destx; + 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); - for (;height > 0; height--){ + drect += destskip; + srect += srcskip; + } - memcpy(drect,srect, width * sizeof(int)); - drect += destx; - srect += srcx; + 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); - if (do_float) { - memcpy(drectf,srectf, width * sizeof(float) * 4); - drectf += destx; - srectf += srcx; - } + drectf += destskip*4; + srectf += srcskip*4; + } + } } } +void IMB_rectblend_torus(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, + int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode) +{ + int origw, origh, w, h; + + /* convert destination and source coordinates too be withing image */ + destx = destx % dbuf->x; + if (destx < 0) destx += dbuf->x; + desty = desty % dbuf->y; + if (desty < 0) desty += dbuf->y; + srcx = srcx % sbuf->x; + if (srcx < 0) srcx += sbuf->x; + 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 and blend */ + IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h); + IMB_rectblend(dbuf, sbuf, destx, desty, srcx, srcy, w, h, mode); + + /* do 3 other rects if needed */ + if (w < origw) + IMB_rectblend(dbuf, sbuf, (destx+w)%dbuf->x, desty, (srcx+w)%sbuf->x, srcy, + origw-w, h, mode); + if (h < origh) + IMB_rectblend(dbuf, sbuf, destx, (desty+h)%dbuf->y, srcx, (srcy+h)%sbuf->y, + w, origh-h, mode); + if ((w < origw) && (h < origh)) + IMB_rectblend(dbuf, sbuf, (destx+w)%dbuf->x, (desty+h)%dbuf->y, + (srcx+w)%sbuf->x, (srcy+h)%sbuf->y, origw-w, origh-h, mode); +} + +/* fill */ + void IMB_rectfill(struct ImBuf *drect, float col[4]) { int num; unsigned int *rrect = drect->rect; - unsigned char *spot; + char ccol[4]; + + ccol[0]= (int)(col[0]*255); + ccol[1]= (int)(col[1]*255); + ccol[2]= (int)(col[2]*255); + ccol[3]= (int)(col[3]*255); num = drect->x * drect->y; - for (;num > 0; num--) { - spot = (unsigned char *)rrect; - spot[0] = (int)(col[0]*255); - spot[1] = (int)(col[1]*255); - spot[2] = (int)(col[2]*255); - spot[3] = (int)(col[3]*255); - *rrect++; - } + for (;num > 0; num--) + *rrect++ = *((unsigned int*)ccol); + if(drect->rect_float) { float *rrectf = drect->rect_float; diff --git a/source/blender/include/blendef.h b/source/blender/include/blendef.h index fde70e4a871..c7cc268de19 100644 --- a/source/blender/include/blendef.h +++ b/source/blender/include/blendef.h @@ -320,6 +320,8 @@ #define B_SIMABRUSHDELETE 375 #define B_SIMABRUSHLOCAL 376 #define B_SIMABRUSHCHANGE 377 +#define B_SIMABTEXBROWSE 378 +#define B_SIMABTEXDELETE 379 /* BUTS: 400 */ #define B_BUTSHOME 401 diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index adcf13b0f55..366c7dfd658 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -541,6 +541,7 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la #define B_BRUSHDELETE 2852 #define B_BRUSHLOCAL 2853 #define B_BRUSHCHANGE 2854 +#define B_BTEXBROWSE 2855 /* *********************** */ #define B_RADIOBUTS 3000 diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 8372e004fcb..1d620de8979 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -32,6 +32,13 @@ #include "DNA_ID.h" +#ifndef MAX_MTEX +#define MAX_MTEX 10 +#endif + +struct MTex; +struct Image; + typedef struct Brush { ID id; @@ -44,6 +51,9 @@ typedef struct Brush { float rgb[3]; /* color */ float alpha; /* opacity */ + short texact, pad; + struct MTex *mtex[10]; + struct Clone { struct Image *image; /* image for clone tool */ float offset[2]; /* offset of clone image from canvas */ diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h index 63d05f9429b..b8ebd50c66e 100644 --- a/source/blender/render/extern/include/RE_render_ext.h +++ b/source/blender/render/extern/include/RE_render_ext.h @@ -44,8 +44,8 @@ struct Render; struct MTex; void RE_zbufferall_radio(struct RadView *vw, struct RNode **rg_elem, int rg_totelem, struct Render *re); -/* effect.c and editmesh_modes. */ -void externtex(struct MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta); +/* effect.c, editmesh_modes.c and brush.c, returns 1 if rgb, 0 otherwise */ +int externtex(struct MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta); #endif /* RE_RENDER_EXT_H */ diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index d3e8516549f..ec3d5e004a4 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -2362,7 +2362,7 @@ void do_lamp_tex(LampRen *la, float *lavec, ShadeInput *shi, float *colf) /* ------------------------------------------------------------------------- */ -void externtex(MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta) +int externtex(MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta) { Tex *tex; TexResult texr; @@ -2404,6 +2404,8 @@ void externtex(MTex *mtex, float *vec, float *tin, float *tr, float *tg, float * *tg= texr.tg; *tb= texr.tb; *ta= texr.ta; + + return (rgb != 0); } diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 31fdf5b7b06..cf2edc8d28b 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -3889,6 +3889,23 @@ void do_fpaintbuts(unsigned short event) } } break; + case B_BTEXBROWSE: + if(G.scene->toolsettings->imapaint.brush==0) return; + if(G.buts->menunr==-2) { + MTex *mtex= G.scene->toolsettings->imapaint.brush->mtex[0]; + ID *id= (ID*)((mtex)? mtex->tex: NULL); + activate_databrowse(id, ID_TE, 0, B_BTEXBROWSE, &G.buts->menunr, do_global_buttons); + break; + } + else if(G.buts->menunr < 0) break; + + if(brush_texture_set_nr(G.scene->toolsettings->imapaint.brush, G.buts->menunr)) { + BIF_undo_push("Browse Brush Texture"); + allqueue(REDRAWBUTSSHADING, 0); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWIMAGE, 0); + } + break; } } diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index a2bf2082294..a81d690cc91 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -41,6 +41,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_brush_types.h" #include "DNA_curve_types.h" #include "DNA_image_types.h" #include "DNA_lamp_types.h" @@ -1215,7 +1216,7 @@ static void texture_panel_colors(Tex *tex) } -static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *la, bNode *node) +static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *la, bNode *node, Brush *br) { MTex *mt=NULL; uiBlock *block; @@ -1236,6 +1237,7 @@ static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *l if(ma) idfrom= &ma->id; else if(wrld) idfrom= &wrld->id; else if(la) idfrom= &la->id; + else if(br) idfrom= &br->id; else idfrom= NULL; uiBlockSetCol(block, TH_BUT_SETTING2); @@ -1248,8 +1250,11 @@ static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *l else if(la) { std_libbuttons(block, 10, 180, 0, NULL, B_LTEXBROWSE, ID_TE, 0, id, idfrom, &(G.buts->texnr), B_TEXALONE, B_TEXLOCAL, B_TEXDELETE, B_AUTOTEXNAME, B_KEEPDATA); } + else if(br) { + std_libbuttons(block, 10, 180, 0, NULL, B_BTEXBROWSE, ID_TE, 0, id, idfrom, &(G.buts->texnr), B_TEXALONE, B_TEXLOCAL, B_TEXDELETE, B_AUTOTEXNAME, B_KEEPDATA); + } else if(node) { - + } uiBlockSetCol(block, TH_BUT_NEUTRAL); @@ -1262,8 +1267,9 @@ static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *l for(a= 0; amtex[a]; - else if(wrld) mt= wrld->mtex[a]; - else if(la) mt= la->mtex[a]; + else if(wrld) mt= wrld->mtex[a]; + else if(la) mt= la->mtex[a]; + else if(br) mt= br->mtex[a]; if(mt && mt->tex) splitIDname(mt->tex->id.name+2, str, &loos); else strcpy(str, ""); @@ -1281,6 +1287,10 @@ static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *l uiDefButS(block, ROW, B_TEXCHANNEL, str, 10,yco,140,19, &(la->texact), 0.0, (float)a, 0, 0, ""); yco-= 20; } + else if(br) { + uiDefButS(block, ROW, B_TEXCHANNEL, str, 10,yco,140,19, &(br->texact), 0.0, (float)a, 0, 0, ""); + yco-= 20; + } } uiBlockEndAlign(block); } @@ -1323,6 +1333,7 @@ static void texture_panel_preview(MTex *mtex, int preview) uiDefButC(block, ROW, B_TEXREDR_PRV, "Mat", 200,175,80,25, &G.buts->texfrom, 3.0, 0.0, 0, 0, "Displays the textures of the active material"); uiDefButC(block, ROW, B_TEXREDR_PRV, "World", 200,150,80,25, &G.buts->texfrom, 3.0, 1.0, 0, 0, "Displays the textures of the world block"); uiDefButC(block, ROW, B_TEXREDR_PRV, "Lamp", 200,125,80,25, &G.buts->texfrom, 3.0, 2.0, 0, 0, "Displays the textures of the selected lamp"); + uiDefButC(block, ROW, B_TEXREDR_PRV, "Brush", 200,100,80,25, &G.buts->texfrom, 3.0, 3.0, 0, 0, "Displays the textures of the selected lamp"); uiBlockEndAlign(block); if(mtex && mtex->tex) @@ -3399,6 +3410,7 @@ void world_panels() void texture_panels() { Material *ma=NULL; + Brush *br=NULL; Lamp *la=NULL; World *wrld=NULL; bNode *node=NULL; @@ -3431,13 +3443,17 @@ void texture_panels() mtex= la->mtex[ la->texact ]; } } + else if(G.buts->texfrom==3) { + br= G.scene->toolsettings->imapaint.brush; + if(br) mtex= br->mtex[br->texact]; + } - texture_panel_preview(mtex, ma || wrld || la || node); // for 'from' buttons + texture_panel_preview(mtex, ma || wrld || la || br || node); // for 'from' buttons - if(ma || wrld || la || node) { + if(ma || wrld || la || br || node) { Tex *tex= NULL; - texture_panel_texture(mtex, ma, wrld, la, node); + texture_panel_texture(mtex, ma, wrld, la, node, br); if(mtex) tex= mtex->tex; else if(node) tex= (Tex *)node->id; diff --git a/source/blender/src/drawimage.c b/source/blender/src/drawimage.c index f43943ec540..0d1aba9438a 100644 --- a/source/blender/src/drawimage.c +++ b/source/blender/src/drawimage.c @@ -61,6 +61,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "DNA_texture_types.h" #include "DNA_userdef_types.h" #include "BKE_brush.h" @@ -944,6 +945,36 @@ void do_imagebuts(unsigned short event) } } break; + case B_SIMABTEXBROWSE: + if(settings->imapaint.brush) { + Brush *brush= settings->imapaint.brush; + + if(G.sima->menunr==-2) { + MTex *mtex= brush->mtex[brush->texact]; + ID *id= (ID*)((mtex)? mtex->tex: NULL); + activate_databrowse(id, ID_TE, 0, B_SIMABTEXBROWSE, &G.sima->menunr, do_global_buttons); + break; + } + else if(G.sima->menunr < 0) break; + + if(brush_texture_set_nr(brush, G.sima->menunr)) { + BIF_undo_push("Browse Brush Texture"); + allqueue(REDRAWBUTSSHADING, 0); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWIMAGE, 0); + } + } + break; + case B_SIMABTEXDELETE: + if(settings->imapaint.brush) { + if (brush_texture_delete(settings->imapaint.brush)) { + BIF_undo_push("Unlink Brush Texture"); + allqueue(REDRAWBUTSSHADING, 0); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWIMAGE, 0); + } + } + break; } } @@ -1062,6 +1093,12 @@ static void image_panel_paint(short cntrl) // IMAGE_HANDLER_PROPERTIES uiDefButF(block, NUMSLI, B_SIMABRUSHCHANGE, "B ",xco+5,yco,butw,19, &brush->clone.alpha , 0.0, 1.0, 0, 0, "Opacity of clone image display"); } } + else { + uiBlockSetCol(block, TH_BUT_SETTING2); + id= (brush->mtex[0])? (ID*)brush->mtex[0]->tex: NULL; + xco= std_libbuttons(block, 0, yco, 0, NULL, B_SIMABTEXBROWSE, ID_TE, 0, id, NULL, &(G.sima->menunr), 0, 0, B_SIMABTEXDELETE, 0, 0); + uiBlockSetCol(block, TH_AUTO); + } } #if 0 diff --git a/source/blender/src/header_buttonswin.c b/source/blender/src/header_buttonswin.c index dcedee12a6b..6e45644fefe 100644 --- a/source/blender/src/header_buttonswin.c +++ b/source/blender/src/header_buttonswin.c @@ -44,6 +44,7 @@ #include "DNA_ID.h" #include "DNA_armature_types.h" +#include "DNA_brush_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" @@ -321,6 +322,13 @@ void buttons_active_id(ID **id, ID **idfrom) if(mtex) *id= (ID *)mtex->tex; } } + else if(G.buts->texfrom==3) { + Brush *brush= G.scene->toolsettings->imapaint.brush; + if (brush) { + mtex= brush->mtex[brush->texact]; + if(mtex) *id= (ID*)mtex->tex; + } + } } } else if(G.buts->mainb==CONTEXT_OBJECT || G.buts->mainb==CONTEXT_LOGIC) { diff --git a/source/blender/src/headerbuttons.c b/source/blender/src/headerbuttons.c index 3ec3a58f9b3..dd582aa0203 100644 --- a/source/blender/src/headerbuttons.c +++ b/source/blender/src/headerbuttons.c @@ -58,6 +58,7 @@ #include "DNA_ID.h" #include "DNA_action_types.h" #include "DNA_armature_types.h" +#include "DNA_brush_types.h" #include "DNA_camera_types.h" #include "DNA_curve_types.h" #include "DNA_group_types.h" @@ -87,10 +88,11 @@ #include "BKE_utildefines.h" -#include "BKE_constraint.h" #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_blender.h" +#include "BKE_brush.h" +#include "BKE_constraint.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" #include "BKE_exotic.h" @@ -550,6 +552,7 @@ void do_global_buttons(unsigned short event) bAction *act; ID *id, *idtest, *from=NULL; ScrArea *sa; + Brush *br; int nr= 1; char buf[FILE_MAXDIR+FILE_MAXFILE]; @@ -767,7 +770,7 @@ void do_global_buttons(unsigned short event) } } } - else { /* from lamp */ + else if(G.buts->texfrom==2) { /* from lamp */ la= ob->data; if(la && ob->type==OB_LAMP) { /* to be sure */ mtex= la->mtex[ la->texact ]; @@ -781,6 +784,21 @@ void do_global_buttons(unsigned short event) } } } + else { /* from brush */ + br= G.scene->toolsettings->imapaint.brush; + if(br) { + mtex= br->mtex[ br->texact ]; + if(mtex) { + if(mtex->tex) mtex->tex->id.us--; + MEM_freeN(mtex); + br->mtex[ br->texact ]= NULL; + allqueue(REDRAWBUTSSHADING, 0); + allqueue(REDRAWIMAGE, 0); + allqueue(REDRAWIPO, 0); + /*BIF_preview_changed(ID_BR);*/ + } + } + } BIF_undo_push("Unlink Texture"); } break; @@ -1200,7 +1218,7 @@ void do_global_buttons(unsigned short event) } } break; - + case B_IMAGEDELETE: G.sima->image= NULL; image_changed(G.sima, 0); @@ -1244,6 +1262,7 @@ void do_global_buttons(unsigned short event) BIF_undo_push("Auto name"); allqueue(REDRAWBUTSSHADING, 0); allqueue(REDRAWOOPS, 0); + allqueue(REDRAWIMAGE, 0); } break; @@ -1501,6 +1520,7 @@ void do_global_buttons2(short event) World *wrld; ID *idfrom; bAction *act; + Brush *br; /* general: Single User is allowed when from==LOCAL * Make Local is allowed when (from==LOCAL && id==LIB) @@ -1772,6 +1792,20 @@ void do_global_buttons2(short event) } } } + else if(G.buts->texfrom==3) { /* from brush */ + br= G.scene->toolsettings->imapaint.brush; + if(br==0) return; + if(br->id.lib==0) { + mtex= br->mtex[ br->texact ]; + if(mtex->tex && mtex->tex->id.us>1) { + if(okee("Single user")) { + mtex->tex->id.us--; + mtex->tex= copy_texture(mtex->tex); + allqueue(REDRAWIMAGE, 0); + } + } + } + } break; case B_TEXLOCAL: if(G.buts->texfrom==0) { /* from mat */ @@ -1810,6 +1844,19 @@ void do_global_buttons2(short event) } } } + else if(G.buts->texfrom==3) { /* from brush */ + br= G.scene->toolsettings->imapaint.brush; + if(br==0) return; + if(br->id.lib==0) { + mtex= br->mtex[ br->texact ]; + if(mtex->tex && mtex->tex->id.lib) { + if(okee("Make local")) { + make_local_texture(mtex->tex); + allqueue(REDRAWIMAGE, 0); + } + } + } + } break; case B_IPOALONE: diff --git a/source/blender/src/imagepaint.c b/source/blender/src/imagepaint.c index a535cb855ab..f80d5a6723d 100644 --- a/source/blender/src/imagepaint.c +++ b/source/blender/src/imagepaint.c @@ -37,7 +37,6 @@ #include #include #include -#include "PIL_time.h" #ifdef HAVE_CONFIG_H #include @@ -49,7 +48,9 @@ #include "BLI_winstuff.h" #endif #include "BLI_arithb.h" +#include "PIL_time.h" +#include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "DNA_brush_types.h" @@ -84,326 +85,99 @@ #include "blendef.h" #include "mydevice.h" -/* Structs */ - -typedef struct ImagePaintPixmap { - unsigned int width, height, rowbytes, shared; - char *rect; -} ImagePaintPixmap; - -typedef struct ImagePaintBrush { - ImagePaintPixmap *pixmap; - float rgb[3], alpha; - unsigned int inner_radius, outer_radius; - short torus; -} ImagePaintBrush; - -typedef struct ImagePaintState { - float mousepos[2]; /* current mouse position in image pixel coordinates */ - float lastmousepos[2]; /* last mouse position in image pixel coordinates */ - - float accumdistance; /* accumulated distance of brush since last paint op */ - float lastpaintpos[2]; /* position of last paint op */ - - double accumtime; /* accumulated time since last paint op (airbrush) */ - double lasttime; /* time of last update */ - - ImagePaintPixmap *canvas; - ImagePaintPixmap *clonecanvas; - ImagePaintBrush *brush; - ToolSettings *settings; - short firsttouch; -} ImagePaintState; - -/* ImagePaintPixmap */ +/* ImagePaint Utilities */ #define IMAPAINT_FLOAT_TO_CHAR(f) ((char)(f*255)) #define IMAPAINT_CHAR_TO_FLOAT(c) (c/255.0f) -#define IMAPAINT_FLOAT_CLAMP(f) ((f < 0.0)? 0.0: (f > 1.0)? 1.0: f) #define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f) { c[0]=IMAPAINT_FLOAT_TO_CHAR(f[0]); \ c[1]=IMAPAINT_FLOAT_TO_CHAR(f[1]); c[2]=IMAPAINT_FLOAT_TO_CHAR(f[2]); } -#define IMAPAINT_FLOAT_RGBA_TO_CHAR(c, f) { \ - c[0]=IMAPAINT_FLOAT_TO_CHAR(f[0]); c[1]=IMAPAINT_FLOAT_TO_CHAR(f[1]); \ - c[2]=IMAPAINT_FLOAT_TO_CHAR(f[2]); c[2]=IMAPAINT_FLOAT_TO_CHAR(f[3]);} #define IMAPAINT_CHAR_RGB_TO_FLOAT(f, c) { f[0]=IMAPAINT_CHAR_TO_FLOAT(c[0]); \ f[1]=IMAPAINT_CHAR_TO_FLOAT(c[1]); f[2]=IMAPAINT_CHAR_TO_FLOAT(c[2]); } -#define IMAPAINT_CHAR_RGBA_TO_FLOAT(f, c) { \ - f[0]=IMAPAINT_CHAR_TO_FLOAT(c[0]); f[1]=IMAPAINT_CHAR_TO_FLOAT(c[1]); \ - f[2]=IMAPAINT_CHAR_TO_FLOAT(c[2]); f[3]=IMAPAINT_CHAR_TO_FLOAT(c[3]); } - #define IMAPAINT_FLOAT_RGB_COPY(a, b) VECCOPY(a, b) -#define IMAPAINT_FLOAT_RGB_ADD(a, b) VECADD(a, a, b) - -#define IMAPAINT_RGB_COPY(a, b) { a[0]=b[0]; a[1]=b[1]; a[2]=b[2]; } -#define IMAPAINT_RGBA_COPY(a, b) { *((int*)a)=*((int*)b); } -static ImagePaintPixmap *imapaint_pixmap_new(unsigned int w, unsigned int h, char *rect) +static void imapaint_blend_line(ImBuf *ibuf, ImBuf *ibufb, float *start, float *end) { - ImagePaintPixmap *pm = MEM_callocN(sizeof(ImagePaintPixmap), "ImagePaintPixmap"); - - pm->width = w; - pm->height = h; - pm->rowbytes = sizeof(char)*w*4; - - if (rect) { - pm->rect = rect; - pm->shared = 1; - } - else - pm->rect = MEM_mallocN(pm->rowbytes*h, "ImagePaintPixmapRect"); - - return pm; -} - -static void imapaint_pixmap_free(ImagePaintPixmap *pm) -{ - if (!pm->shared) - MEM_freeN(pm->rect); - MEM_freeN(pm); -} - -/* ImagePaintBrush */ - -static void imapaint_brush_pixmap_refresh(ImagePaintBrush *brush) -{ - ImagePaintPixmap *pm = brush->pixmap; - char *dst, src[4], src_alpha[4]; - unsigned int y, x, outer, inner; - float w_2, h_2, dX, dY, d, a; - - w_2 = pm->width/2.0f; - h_2 = pm->height/2.0f; - - outer = brush->outer_radius; - inner = brush->inner_radius; - - IMAPAINT_FLOAT_RGB_TO_CHAR(src, brush->rgb); - src[3] = 0; - IMAPAINT_RGB_COPY(src_alpha, src); - src_alpha[3] = IMAPAINT_FLOAT_TO_CHAR(brush->alpha); + float numsteps, t, pos[2]; + int step, d[2], ipos[2]; - for (y=0; y < pm->height; y++) { - dst = pm->rect + y*pm->rowbytes; + d[0] = (int)(end[0] - start[0]); + d[1] = (int)(end[1] - start[1]); + numsteps = sqrt(d[0]*d[0] + d[1]*d[1])/(ibufb->x/4.0f); - for (x=0; x < pm->width; x++, dst+=4) { - dX = x + 0.5f - w_2; - dY = y + 0.5f - h_2; - d = sqrt(dX*dX + dY*dY); + if(numsteps < 1.0) + numsteps = 1.0f; - if (d <= inner) { - IMAPAINT_RGBA_COPY(dst, src_alpha); - } - else if ((d < outer) && (inner < outer)) { - a = sqrt((d - inner)/(outer - inner)); - a = (1 - a)*brush->alpha; + for (step=0; step < numsteps; step++) { + t = (step+1)/numsteps; + pos[0] = start[0] + d[0]*t; + pos[1] = start[1] + d[1]*t; - IMAPAINT_RGB_COPY(dst, src); - dst[3] = IMAPAINT_FLOAT_TO_CHAR(a); - } - else { - IMAPAINT_RGBA_COPY(dst, src); - } - } + ipos[0]= (int)(pos[0] - ibufb->x/2); + ipos[1]= (int)(pos[1] - ibufb->y/2); + IMB_rectblend(ibuf, ibufb, ipos[0], ipos[1], 0, 0, + ibufb->x, ibufb->y, IMB_BLEND_MIX); } } -static void imapaint_brush_set_radius_ratio(ImagePaintBrush *brush, float ratio) -{ - ImagePaintPixmap *pm = brush->pixmap; - unsigned int si, w_2 = pm->width/2, h_2 = pm->height/2; - - si = (pm->width < pm->height)? pm->width: pm->height; - brush->inner_radius = (int)((ratio*si)/2); - brush->outer_radius = si/2; - - if (brush->outer_radius > w_2) - brush->outer_radius = w_2; - if (brush->outer_radius > h_2) - brush->outer_radius = h_2; - if (brush->inner_radius > brush->outer_radius) - brush->inner_radius = brush->outer_radius; -} - -static ImagePaintBrush *imapaint_brush_new(unsigned int w, unsigned int h, float *rgb, float alpha, float radius_ratio) -{ - ImagePaintBrush *brush = MEM_callocN(sizeof(ImagePaintBrush), "ImagePaintBrush"); - - IMAPAINT_FLOAT_RGB_COPY(brush->rgb, rgb); - brush->alpha = alpha; - brush->pixmap = imapaint_pixmap_new(w, h, NULL); - - imapaint_brush_set_radius_ratio(brush, radius_ratio); - imapaint_brush_pixmap_refresh(brush); - - return brush; -} - -static void imapaint_brush_free(ImagePaintBrush *brush) -{ - imapaint_pixmap_free(brush->pixmap); - MEM_freeN(brush); -} - -/* ImagePaintPixmap Utilities */ - -static char *imapaint_pixmap_get_rgba(ImagePaintPixmap *pm, unsigned int x, unsigned int y) -{ - return &pm->rect[pm->rowbytes*y + x*4]; -} - -static char *imapaint_pixmap_get_rgba_torus(ImagePaintPixmap *pm, unsigned int x, unsigned int y) -{ - x %= pm->width; - y %= pm->height; - - return &pm->rect[pm->rowbytes*y + x*4]; -} - -static void imapaint_pixmap_clip(ImagePaintPixmap *pm, ImagePaintPixmap *bpm, float *pos, unsigned int *off, unsigned int *boff, unsigned int *dim) +static void imapaint_ibuf_get_set_rgb(ImBuf *ibuf, int x, int y, short torus, short set, float *rgb) { - int x = (int)(pos[0] - bpm->width/2); - int y = (int)(pos[1] - bpm->height/2); - - dim[0] = bpm->width; - dim[1] = bpm->height; - - if (((x + (int)dim[0]) <= 0) || (x >= (int)pm->width) || - ((y + (int)dim[1]) <= 0) || (y >= (int)pm->height)) { - dim[0] = 0; - dim[1] = 0; - return; + if (torus) { + x %= ibuf->x; + if (x < 0) x += ibuf->x; + y %= ibuf->y; + if (y < 0) y += ibuf->y; } - if (x < 0) { - dim[0] += x; - off[0] = 0; - boff[0] = -x; - } - else { - off[0] = x; - boff[0] = 0; - } + if (ibuf->rect_float) { + float *rrgbf = ibuf->rect_float + (ibuf->x*y + x)*4; - if (y < 0) { - dim[1] += y; - off[1] = 0; - boff[1] = -y; + if (set) IMAPAINT_FLOAT_RGB_COPY(rrgbf, rgb) + else IMAPAINT_FLOAT_RGB_COPY(rgb, rrgbf) } else { - off[1] = y; - boff[1] = 0; - } - - if (off[0] + dim[0] > pm->width) - dim[0] -= (off[0] + dim[0]) - pm->width; - if (off[1] + dim[1] > pm->height) - dim[1] -= (off[1] + dim[1]) - pm->height; -} - -static void imapaint_pixmap_blend(ImagePaintPixmap *pm, ImagePaintPixmap *bpm, float *pos, short mode) -{ - unsigned int x, y, dim[2], out_off[2], in_off[2]; - char *out, *in; - - imapaint_pixmap_clip(pm, bpm, pos, out_off, in_off, dim); - - if ((dim[0] == 0) || (dim[1] == 0)) - return; - - for (y=0; y < dim[1]; y++) { - out = imapaint_pixmap_get_rgba(pm, out_off[0], out_off[1]+y); - in = imapaint_pixmap_get_rgba(bpm, in_off[0], in_off[1]+y); - - for (x=0; x < dim[0]; x++, out+=4, in+=4) - brush_blend_rgb(out, out, in, in[3], mode); - } -} - -static void imapaint_pixmap_blend_torus(ImagePaintPixmap *pm, ImagePaintPixmap *bpm, float *pos, short mode) -{ - unsigned int x, y, out_off[2], mx, my; - char *out, *in; - - out_off[0] = (int)(pos[0] - bpm->width/2); - out_off[1] = (int)(pos[1] - bpm->height/2); + char *rrgb = (char*)ibuf->rect + (ibuf->x*y + x)*4; - for (y=0; y < bpm->height; y++) { - in = imapaint_pixmap_get_rgba(bpm, 0, y); - - for (x=0; x < bpm->width; x++, out+=4, in+=4) { - mx = (out_off[0]+x) % pm->width; - my = (out_off[1]+y) % pm->height; - out = imapaint_pixmap_get_rgba(pm, mx, my); - - brush_blend_rgb(out, out, in, in[3], mode); - } + if (set) IMAPAINT_FLOAT_RGB_TO_CHAR(rrgb, rgb) + else IMAPAINT_CHAR_RGB_TO_FLOAT(rgb, rrgb) } } -static int imapaint_pixmap_add_if(ImagePaintPixmap *pm, unsigned int x, unsigned int y, float *outrgb, short torus) +static int imapaint_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus) { - char *inrgb; - float finrgb[3]; + float inrgb[3]; - if ((x >= pm->width) || (y >= pm->height)) { - if (torus) - inrgb = imapaint_pixmap_get_rgba_torus(pm, x, y); - else - return 0; + if ((x >= ibuf->x) || (y >= ibuf->y)) { + if (torus) imapaint_ibuf_get_set_rgb(ibuf, x, y, 1, 0, inrgb); + else return 0; } - else - inrgb = imapaint_pixmap_get_rgba(pm, x, y); + else imapaint_ibuf_get_set_rgb(ibuf, x, y, 0, 0, inrgb); - IMAPAINT_CHAR_RGB_TO_FLOAT(finrgb, inrgb); - IMAPAINT_FLOAT_RGB_ADD(outrgb, finrgb); + outrgb[0] += inrgb[0]; + outrgb[1] += inrgb[1]; + outrgb[2] += inrgb[2]; return 1; } -/* ImagePaintPixmap Tools */ +/* ImagePaint Tools */ -static void imapaint_blend_line(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *start, float *end) +static void imapaint_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, short torus) { - float numsteps, t, pos[2]; - int step, d[2]; - - d[0] = (int)(end[0] - start[0]); - d[1] = (int)(end[1] - start[1]); - numsteps = sqrt(d[0]*d[0] + d[1]*d[1])/(brush->pixmap->width/4.0f); - - if(numsteps < 1.0) - numsteps = 1.0f; - - for (step=0; step < numsteps; step++) { - t = (step+1)/numsteps; - pos[0] = start[0] + d[0]*t; - pos[1] = start[1] + d[1]*t; + int x, y, count, xi, yi, xo, yo; + int out_off[2], in_off[2], dim[2]; + float outrgb[3]; - if (brush->torus) - imapaint_pixmap_blend_torus(pm, brush->pixmap, pos, BRUSH_BLEND_MIX); - else - imapaint_pixmap_blend(pm, brush->pixmap, pos, BRUSH_BLEND_MIX); - } -} + 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; -static void imapaint_lift_soften(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *pos, short torus) -{ - ImagePaintPixmap *bpm = brush->pixmap; - unsigned int x, y, count, xi, yi, xo, yo; - unsigned int out_off[2], in_off[2], dim[2]; - float outrgb[3]; - char *inrgb, *out; + if (!torus) { + IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0], + &out_off[1], &dim[0], &dim[1]); - if (torus) { - dim[0] = bpm->width; - dim[1] = bpm->width; - in_off[0] = (int)(pos[0] - bpm->width/2); - in_off[1] = (int)(pos[1] - bpm->width/2); - out_off[0] = out_off[1] = 0; - } - else { - imapaint_pixmap_clip(pm, bpm, pos, in_off, out_off, dim); if ((dim[0] == 0) || (dim[1] == 0)) return; } @@ -413,164 +187,126 @@ static void imapaint_lift_soften(ImagePaintPixmap *pm, ImagePaintBrush *brush, f /* get input pixel */ xi = in_off[0] + x; yi = in_off[1] + y; - if (torus) - inrgb = imapaint_pixmap_get_rgba_torus(pm, xi, yi); - else - inrgb = imapaint_pixmap_get_rgba(pm, xi, yi); - /* sum and average surrounding pixels */ count = 1; - IMAPAINT_CHAR_RGB_TO_FLOAT(outrgb, inrgb); -#if 0 - if (sharpen) - IMAPAINT_FLOAT_RGB_COPY(finrgb, outrgb); -#endif + imapaint_ibuf_get_set_rgb(ibuf, xi, yi, torus, 0, outrgb); - count += imapaint_pixmap_add_if(pm, xi-1, yi-1, outrgb, torus); - count += imapaint_pixmap_add_if(pm, xi-1, yi , outrgb, torus); - count += imapaint_pixmap_add_if(pm, xi-1, yi+1, outrgb, torus); + count += imapaint_ibuf_add_if(ibuf, xi-1, yi-1, outrgb, torus); + count += imapaint_ibuf_add_if(ibuf, xi-1, yi , outrgb, torus); + count += imapaint_ibuf_add_if(ibuf, xi-1, yi+1, outrgb, torus); - count += imapaint_pixmap_add_if(pm, xi , yi-1, outrgb, torus); - count += imapaint_pixmap_add_if(pm, xi , yi+1, outrgb, torus); + count += imapaint_ibuf_add_if(ibuf, xi , yi-1, outrgb, torus); + count += imapaint_ibuf_add_if(ibuf, xi , yi+1, outrgb, torus); - count += imapaint_pixmap_add_if(pm, xi+1, yi-1, outrgb, torus); - count += imapaint_pixmap_add_if(pm, xi+1, yi , outrgb, torus); - count += imapaint_pixmap_add_if(pm, xi+1, yi+1, outrgb, torus); + count += imapaint_ibuf_add_if(ibuf, xi+1, yi-1, outrgb, torus); + count += imapaint_ibuf_add_if(ibuf, xi+1, yi , outrgb, torus); + count += imapaint_ibuf_add_if(ibuf, xi+1, yi+1, outrgb, torus); outrgb[0] /= count; outrgb[1] /= count; outrgb[2] /= count; -#if 0 - if (sharpen) { - /* unsharp masking - creates ugly artifacts and is disabled - for now, needs some sort of clamping to reduce artifacts */ - outrgb[0] = 2*finrgb[0] - outrgb[0]; - outrgb[1] = 2*finrgb[1] - outrgb[1]; - outrgb[2] = 2*finrgb[2] - outrgb[2]; - - outrgb[0] = IMAPAINT_FLOAT_CLAMP(outrgb[0]); - outrgb[1] = IMAPAINT_FLOAT_CLAMP(outrgb[1]); - outrgb[2] = IMAPAINT_FLOAT_CLAMP(outrgb[2]); - } -#endif - /* write into brush buffer */ xo = out_off[0] + x; yo = out_off[1] + y; - out = imapaint_pixmap_get_rgba(bpm, xo, yo); - IMAPAINT_FLOAT_RGB_TO_CHAR(out, outrgb); + imapaint_ibuf_get_set_rgb(ibufb, xo, yo, 0, 1, outrgb); } } } -static void imapaint_lift_smear(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *pos) +static void imapaint_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos) { - ImagePaintPixmap *bpm = brush->pixmap; - int in_off[2], x, y; - char *out, *in; - - in_off[0] = (int)(pos[0] - bpm->width/2); - in_off[1] = (int)(pos[1] - bpm->height/2); - - for (y=0; y < bpm->height; y++) { - out = imapaint_pixmap_get_rgba(bpm, 0, y); - for (x=0; x < bpm->width; x++, out+=4) { - in = imapaint_pixmap_get_rgba_torus(pm, in_off[0]+x, in_off[1]+y); - IMAPAINT_RGB_COPY(out, in); - } - } + IMB_rectblend_torus(ibufb, ibuf, 0, 0, pos[0], pos[1], + ibufb->x, ibufb->y, IMB_BLEND_COPY_RGB); } -static void imapaint_lift_clone(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *pos) +static ImBuf *imapaint_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos) { - ImagePaintPixmap *bpm = brush->pixmap; - int in_off[2], x, y, xi, yi; - char *out, *in; - - /* we overwrite alphas for pixels outside clone, so need to reload them */ - imapaint_brush_pixmap_refresh(brush); + /* 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->depth, ibufb->flags, 0); + + IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h); + IMB_rectblend(clonebuf, ibuf, destx, desty, srcx, srcy, w, h, + IMB_BLEND_COPY_RGB); + IMB_rectblend(clonebuf, ibufb, destx, desty, destx, desty, w, h, + IMB_BLEND_COPY_ALPHA); + + return clonebuf; +} - in_off[0] = (int)(pos[0] - bpm->width/2); - in_off[1] = (int)(pos[1] - bpm->height/2); +/* ImagePaint state and operations */ - for (y=0; y < bpm->height; y++) { - out = imapaint_pixmap_get_rgba(bpm, 0, y); - for (x=0; x < bpm->width; x++, out+=4) { - xi = in_off[0] + x; - yi = in_off[1] + y; +typedef struct ImagePaintState { + Brush *brush; + short tool; + ImBuf *canvas; + ImBuf *clonecanvas; +} ImagePaintState; - if ((xi < 0) || (yi < 0) || (xi >= pm->width) || (yi >= pm->height)) { - out[0] = out[1] = out[2] = out[3] = 0; - } - else { - in = imapaint_pixmap_get_rgba(pm, xi, yi); - IMAPAINT_RGB_COPY(out, in); - } - } - } +static void imapaint_convert_brushco(ImBuf *ibufb, float *pos, int *ipos) +{ + ipos[0]= (int)(pos[0] - ibufb->x/2); + ipos[1]= (int)(pos[1] - ibufb->y/2); } -/* 2D image paint */ - -static int imapaint_state_init(ImagePaintState *state, ToolSettings *settings) +static int imapaint_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *pos) { - Brush *brush= settings->imapaint.brush; + ImagePaintState s= *((ImagePaintState*)state); + ImBuf *clonebuf= NULL; + short torus= s.brush->flag & BRUSH_TORUS; + short blend= s.brush->blend; + float *offset= s.brush->clone.offset; + float liftpos[2]; + int bpos[2], blastpos[2], bliftpos[2]; - if (!brush) + if ((s.tool == PAINT_TOOL_SMEAR) && (lastpos[0]==pos[0]) && (lastpos[1]==pos[1])) return 0; - memset(state, 0, sizeof(*state)); - state->firsttouch= 1; - state->lasttime= PIL_check_seconds_timer(); - state->settings= settings; + imapaint_convert_brushco(ibufb, pos, bpos); + + /* lift from canvas */ + if(s.tool == PAINT_TOOL_SOFTEN) { + imapaint_lift_soften(s.canvas, ibufb, bpos, torus); + } + else if(s.tool == PAINT_TOOL_SMEAR) { + imapaint_convert_brushco(ibufb, lastpos, blastpos); + imapaint_lift_smear(s.canvas, ibufb, blastpos); + } + else if(s.tool == PAINT_TOOL_CLONE && s.clonecanvas) { + liftpos[0]= pos[0] - offset[0]*s.canvas->x; + liftpos[1]= pos[1] - offset[1]*s.canvas->y; - /* initialize paint settings */ - state->settings->imapaint.flag |= IMAGEPAINT_DRAWING; + imapaint_convert_brushco(ibufb, liftpos, bliftpos); + clonebuf= imapaint_lift_clone(s.clonecanvas, ibufb, bliftpos); + } - /* create brush */ - state->brush= imapaint_brush_new(brush->size, brush->size, brush->rgb, - brush->alpha, brush->innerradius); + /* blend into canvas */ + if(torus) + IMB_rectblend_torus(s.canvas, (clonebuf)? clonebuf: ibufb, + bpos[0], bpos[1], 0, 0, ibufb->x, ibufb->y, blend); + else + IMB_rectblend(s.canvas, (clonebuf)? clonebuf: ibufb, + bpos[0], bpos[1], 0, 0, ibufb->x, ibufb->y, blend); + + if(clonebuf) IMB_freeImBuf(clonebuf); return 1; } -static void imapaint_state_free(ImagePaintState *state) -{ - state->settings->imapaint.flag &= ~IMAGEPAINT_DRAWING; +/* 2D ImagePaint */ - if(state->brush) imapaint_brush_free(state->brush); - if(state->canvas) imapaint_pixmap_free(state->canvas); - if(state->clonecanvas) imapaint_pixmap_free(state->clonecanvas); +static void imapaint_compute_uvco(short *mval, float *uv) +{ + areamouseco_to_ipoco(G.v2d, mval, &uv[0], &uv[1]); } -static int imapaint_canvas_init(ImagePaintState *state) +static void imapaint_compute_imageco(ImBuf *ibuf, short *mval, float *mousepos) { - Brush *brush= state->settings->imapaint.brush; - ImBuf *ibuf= NULL, *cloneibuf= NULL; - - /* verify that we can paint and create canvas */ - if(!G.sima->image || !G.sima->image->ibuf || !G.sima->image->ibuf->rect) - return 0; - else if(G.sima->image->packedfile) - return 0; - - ibuf= G.sima->image->ibuf; - state->canvas= imapaint_pixmap_new(ibuf->x, ibuf->y, (char*)ibuf->rect); - - /* create clone canvas */ - if(brush && (state->settings->imapaint.tool == PAINT_TOOL_CLONE)) { - int w, h; - if(!brush->clone.image || !brush->clone.image->ibuf) - return 0; - - cloneibuf= brush->clone.image->ibuf; - w = cloneibuf->x; - h = cloneibuf->y; - state->clonecanvas= imapaint_pixmap_new(w, h, (char*)cloneibuf->rect); - } - - return 1; + areamouseco_to_ipoco(G.v2d, mval, &mousepos[0], &mousepos[1]); + mousepos[0] *= ibuf->x; + mousepos[1] *= ibuf->y; } void imapaint_redraw_tool(void) @@ -600,191 +336,126 @@ static void imapaint_redraw(int final, int painted) allqueue(REDRAWHEADERS, 0); } -static void imapaint_compute_uvco(short *mval, float *uv) -{ - areamouseco_to_ipoco(G.v2d, mval, &uv[0], &uv[1]); -} - -static void imapaint_compute_imageco(ImagePaintPixmap *pm, short *mval, float *mousepos) +static int imapaint_canvas_init(Brush *brush, short tool, ImBuf **canvas, ImBuf **clonecanvas, short *freefloat) { - areamouseco_to_ipoco(G.v2d, mval, &mousepos[0], &mousepos[1]); - mousepos[0] *= pm->width; - mousepos[1] *= pm->height; -} - -static void imapaint_paint_op(ImagePaintState *s, float *lastpos, float *pos) -{ - ImagePaintPixmap *canvas= s->canvas; - ImagePaintPixmap *clonecanvas= s->clonecanvas; - ImagePaintBrush *brush= s->brush; - short tool= s->settings->imapaint.tool; - short torus= s->settings->imapaint.brush->flag & BRUSH_TORUS; - short blend= s->settings->imapaint.brush->blend; - float *offset= s->settings->imapaint.brush->clone.offset; - float liftpos[2]; - - /* lift from canvas */ - if(tool == PAINT_TOOL_SOFTEN) { - imapaint_lift_soften(canvas, brush, pos, torus); - } - else if(tool == PAINT_TOOL_SMEAR) { - imapaint_lift_smear(canvas, brush, lastpos); - } - else if(tool == PAINT_TOOL_CLONE && clonecanvas) { - liftpos[0]= pos[0] - offset[0]*clonecanvas->width; - liftpos[1]= pos[1] - offset[1]*clonecanvas->height; + Image *ima= G.sima->image; - imapaint_lift_clone(clonecanvas, brush, liftpos); - } - - /* blend into canvas */ - if (torus) - imapaint_pixmap_blend_torus(canvas, brush->pixmap, pos, blend); - else - imapaint_pixmap_blend(canvas, brush->pixmap, pos, blend); -} - -static void imapaint_state_do(ImagePaintState *s, short *painted) -{ - if (s->firsttouch) { - /* always paint exactly once on first touch */ - if (s->settings->imapaint.tool != PAINT_TOOL_SMEAR) - imapaint_paint_op(s, s->mousepos, s->mousepos); - - s->firsttouch= 0; - s->lastpaintpos[0]= s->mousepos[0]; - s->lastpaintpos[1]= s->mousepos[1]; - if (painted) *painted |= 1; - } - else { - Brush *brush= s->settings->imapaint.brush; - float startdistance, spacing, step, paintpos[2], dmousepos[2]; - int totpaintops= 0; - - /* compute brush spacing adapted to brush size */ - spacing= brush->size*brush->spacing*0.01f; - - /* setup starting distance, direction vector and accumulated distance */ - startdistance= s->accumdistance; - Vec2Subf(dmousepos, s->mousepos, s->lastmousepos); - s->accumdistance += Normalise2(dmousepos); + /* verify that we can paint and create canvas */ + if(!ima || !ima->ibuf || !(ima->ibuf->rect || ima->ibuf->rect_float)) + return 0; + else if(ima->packedfile) + return 0; - /* do paint op over unpainted distance */ - while (s->accumdistance >= spacing) { - step= spacing - startdistance; - paintpos[0]= s->lastmousepos[0] + dmousepos[0]*step; - paintpos[1]= s->lastmousepos[1] + dmousepos[1]*step; + *canvas= ima->ibuf; - imapaint_paint_op(s, s->lastpaintpos, paintpos); + /* create clone canvas */ + if(clonecanvas && (tool == PAINT_TOOL_CLONE)) { + ima= brush->clone.image; + if(!ima || !ima->ibuf || !(ima->ibuf->rect || ima->ibuf->rect_float)) + return 0; - s->lastpaintpos[0]= paintpos[0]; - s->lastpaintpos[1]= paintpos[1]; - s->accumdistance -= spacing; - startdistance -= spacing; - totpaintops++; + *clonecanvas= ima->ibuf; - if (painted) *painted |= 1; + if((*canvas)->rect_float && !(*clonecanvas)->rect_float) { + /* temporarily add float rect for cloning */ + *freefloat= 1; + IMB_float_from_rect(*clonecanvas); } - - /* do airbrush paint ops, based on the number of paint ops left over - from regular painting */ - if (brush->flag & BRUSH_AIRBRUSH) { - double curtime= PIL_check_seconds_timer(); - double painttime= brush->rate*totpaintops; - - s->accumtime += curtime - s->lasttime; - if (s->accumtime <= painttime) - s->accumtime= 0.0; - else - s->accumtime -= painttime; - - while (s->accumtime >= brush->rate) { - if (s->settings->imapaint.tool != PAINT_TOOL_SMEAR) - imapaint_paint_op(s, s->mousepos, s->mousepos); - s->accumtime -= brush->rate; - - totpaintops++; - } - - s->lasttime= curtime; + else if(!(*canvas)->rect_float && !(*clonecanvas)->rect) { + *freefloat= 0; + IMB_rect_from_float(*clonecanvas); } - - if ((totpaintops > 0) && painted) *painted |= 1; + else + *freefloat= 0; } + else if(clonecanvas) + *clonecanvas= NULL; + + return 1; } void imagepaint_paint(short mousebutton) { - ImagePaintState state; - short prevmval[2], mval[2], painted, moved; + ImagePaintState s; + BrushPainter *painter; + ToolSettings *settings= G.scene->toolsettings; + short prevmval[2], mval[2], freefloat=0; + float mousepos[2]; + double mousetime; - /* setup data structures */ - if (!(imapaint_state_init(&state, G.scene->toolsettings))) { - return; - } - else if (!imapaint_canvas_init(&state)) { + /* initialize state */ + s.brush= settings->imapaint.brush; + s.tool= settings->imapaint.tool; + + if(!s.brush) return; + if(!imapaint_canvas_init(s.brush, s.tool, &s.canvas, &s.clonecanvas, &freefloat)) { if(G.sima->image && G.sima->image->packedfile) error("Painting in packed images not supported"); - imapaint_state_free(&state); return; } - - /* initialize coordinates and time */ - getmouseco_areawin(mval); - imapaint_compute_imageco(state.canvas, mval, state.mousepos); + settings->imapaint.flag |= IMAGEPAINT_DRAWING; + + /* create painter and paint once */ + painter= brush_painter_new(s.brush); + brush_painter_require_imbuf(painter, ((s.canvas->rect_float)? 1: 0), 0, 0); + + getmouseco_areawin(mval); + mousetime= PIL_check_seconds_timer(); prevmval[0]= mval[0]; prevmval[1]= mval[1]; - state.lastmousepos[0]= state.mousepos[0]; - state.lastmousepos[1]= state.mousepos[1]; - state.lasttime= PIL_check_seconds_timer(); + imapaint_compute_imageco(s.canvas, mval, mousepos); - /* start by painting once */ - imapaint_state_do(&state, NULL); - imapaint_redraw(0, 1); + if(brush_painter_paint(painter, imapaint_paint_op, mousepos, mousetime, &s)) { + if (s.canvas->rect_float) + imb_freerectImBuf(s.canvas); /* force recreate */ + imapaint_redraw(0, 1); + } /* paint loop */ while(get_mbut() & mousebutton) { getmouseco_areawin(mval); - moved= painted= 0; + mousetime= PIL_check_seconds_timer(); if((mval[0] != prevmval[0]) || (mval[1] != prevmval[1])) { prevmval[0]= mval[0]; prevmval[1]= mval[1]; - imapaint_compute_imageco(state.canvas, mval, state.mousepos); - moved= 1; + imapaint_compute_imageco(s.canvas, mval, mousepos); } - else if (!(state.settings->imapaint.brush->flag & BRUSH_AIRBRUSH)) + else if (!(s.brush->flag & BRUSH_AIRBRUSH)) continue; - imapaint_state_do(&state, &painted); - - state.lastmousepos[0]= state.mousepos[0]; - state.lastmousepos[1]= state.mousepos[1]; - - if(painted) { - imapaint_redraw(0, painted); + if(brush_painter_paint(painter, imapaint_paint_op, mousepos, mousetime, &s)) { + if (s.canvas->rect_float) + imb_freerectImBuf(s.canvas); /* force recreate */ + imapaint_redraw(0, 1); } - else if(moved && (state.settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL)) - imapaint_redraw(0, painted); + + /* todo: check if we can wait here to not take up all cpu usage? */ } /* clean up */ - imapaint_state_free(&state); + settings->imapaint.flag &= ~IMAGEPAINT_DRAWING; + s.canvas->userflags |= IB_BITMAPDIRTY; + + if (freefloat) imb_freerectfloatImBuf(s.clonecanvas); + + brush_painter_free(painter); - G.sima->image->ibuf->userflags |= IB_BITMAPDIRTY; imapaint_redraw(1, 0); } +/* 3D TexturePaint */ + /* these will be moved */ int facesel_face_pick(Mesh *me, short *mval, unsigned int *index, short rect); void texpaint_pick_uv(Object *ob, Mesh *mesh, TFace *tf, short *xy, float *mousepos); -static void texpaint_compute_imageco(ImagePaintPixmap *pm, Object *ob, Mesh *mesh, TFace *tf, short *xy, float *imageco) +static void texpaint_compute_imageco(ImBuf *ibuf, Object *ob, Mesh *mesh, TFace *tf, short *xy, float *imageco) { texpaint_pick_uv(ob, mesh, tf, xy, imageco); - imageco[0] *= pm->width; - imageco[1] *= pm->height; + imageco[0] *= ibuf->x; + imageco[1] *= ibuf->y; } void texturepaint_paint(short mousebutton) @@ -795,21 +466,25 @@ void texturepaint_paint(short mousebutton) short xy[2], xy_old[2]; //int a, index; Image *img=NULL, *img_old = NULL; - ImagePaintBrush *brush; - ImagePaintPixmap *canvas = 0; + ImBuf *brush, *canvas = 0; unsigned int face_index; char *warn_packed_file = 0; float uv[2], uv_old[2]; extern VPaint Gvp; - ImBuf *ibuf= NULL; + Brush tmpbrush; ob = OBACT; if (!ob || !(ob->lay & G.vd->lay)) return; me = get_mesh(ob); if (!me) return; - brush = imapaint_brush_new(Gvp.size, Gvp.size, &Gvp.r, Gvp.a, 0.5); - if (!brush) return; + /* create a fake Brush for now - will be replaced soon */ + memset(&tmpbrush, 0, sizeof(Brush)); + tmpbrush.size= Gvp.size; + tmpbrush.alpha= Gvp.a; + tmpbrush.innerradius= 0.5f; + IMAPAINT_FLOAT_RGB_COPY(tmpbrush.rgb, &Gvp.r); + brush = brush_imbuf_new(&tmpbrush, 0, 0, tmpbrush.size); persp(PERSP_VIEW); @@ -828,7 +503,7 @@ void texturepaint_paint(short mousebutton) /* The active face changed, check the texture */ if (face) { img = face->tpage; - ibuf = (img)? img->ibuf: NULL; + canvas = (img)? img->ibuf: NULL; } else { img = 0; @@ -840,21 +515,18 @@ void texturepaint_paint(short mousebutton) texpaint_compute_imageco(canvas, ob, me, face_old, xy, uv); imapaint_blend_line(canvas, brush, uv_old, uv); img_old->ibuf->userflags |= IB_BITMAPDIRTY; - /* Delete old canvas */ - imapaint_pixmap_free(canvas); canvas = 0; } /* Create new canvas and start drawing in the new face. */ if (img) { - if (ibuf && img->packedfile == 0) { + if (canvas && img->packedfile == 0) { /* MAART: skipx is not set most of the times. Make a guess. */ - canvas = imapaint_pixmap_new(ibuf->x, ibuf->y, (char*)ibuf->rect); if (canvas) { texpaint_compute_imageco(canvas, ob, me, face, xy_old, uv_old); texpaint_compute_imageco(canvas, ob, me, face, xy, uv); imapaint_blend_line(canvas, brush, uv_old, uv); - ibuf->userflags |= IB_BITMAPDIRTY; + canvas->userflags |= IB_BITMAPDIRTY; } } else { @@ -880,7 +552,7 @@ void texturepaint_paint(short mousebutton) texpaint_compute_imageco(canvas, ob, me, face, xy_old, uv_old); texpaint_compute_imageco(canvas, ob, me, face, xy, uv); imapaint_blend_line(canvas, brush, uv_old, uv); - ibuf->userflags |= IB_BITMAPDIRTY; + canvas->userflags |= IB_BITMAPDIRTY; } } } @@ -891,7 +563,7 @@ void texturepaint_paint(short mousebutton) /* Get the new (u,v) coordinates */ texpaint_compute_imageco(canvas, ob, me, face, xy, uv); imapaint_blend_line(canvas, brush, uv_old, uv); - ibuf->userflags |= IB_BITMAPDIRTY; + canvas->userflags |= IB_BITMAPDIRTY; } } @@ -912,15 +584,10 @@ void texturepaint_paint(short mousebutton) } } - imapaint_brush_free(brush); - if (canvas) { - imapaint_pixmap_free(canvas); - canvas = 0; - } + IMB_freeImBuf(brush); - if (warn_packed_file) { + if (warn_packed_file) error("Painting in packed images is not supported: %s", warn_packed_file); - } persp(PERSP_WIN); -- cgit v1.2.3