Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2006-08-27 17:29:00 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2006-08-27 17:29:00 +0400
commitb39f4b788dc9c5ccc9430b02852cbc1cbe56eca1 (patch)
tree7a1c91c3d4235db02b231ab5f504b31c2c0e4f15 /source/blender
parent84205fe0e0bfc524b8fd9ba09aedbf98b0b9457b (diff)
Texturepaint now supports all the imagepaint brush settings, with the
exception of the clone tool. One level undo for image- and texturepaint, only storing those tiles that changed. Test to improve texturepaint performance using glTexSubImage2D, only enabled with 2^n sized textures and mipmapping off. Painting a 2048x2048 texture is then pretty smooth here, as long as the geometry is not too complex.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_brush.h13
-rw-r--r--source/blender/blenkernel/intern/brush.c391
-rw-r--r--source/blender/imbuf/intern/rectop.c21
-rw-r--r--source/blender/include/BDR_drawmesh.h2
-rw-r--r--source/blender/include/BDR_imagepaint.h5
-rw-r--r--source/blender/include/butspace.h1
-rw-r--r--source/blender/makesdna/DNA_brush_types.h1
-rw-r--r--source/blender/src/buttons_editing.c76
-rw-r--r--source/blender/src/buttons_shading.c2
-rw-r--r--source/blender/src/drawimage.c1
-rw-r--r--source/blender/src/drawmesh.c28
-rw-r--r--source/blender/src/drawview.c11
-rw-r--r--source/blender/src/editface.c2
-rw-r--r--source/blender/src/header_view3d.c8
-rw-r--r--source/blender/src/imagepaint.c631
-rw-r--r--source/blender/src/space.c16
-rw-r--r--source/blender/src/usiblender.c2
17 files changed, 806 insertions, 405 deletions
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index a55c8913c7f..52f86ef9c41 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -55,8 +55,10 @@ int brush_clone_image_set_nr(struct Brush *brush, int nr);
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);
+float brush_sample_falloff(struct Brush *brush, float dist);
+void brush_sample_tex(struct Brush *brush, float *xy, float *rgba);
+void brush_imbuf_new(struct Brush *brush, short flt, short texfalloff, int size,
+ struct ImBuf **imbuf);
/* painting */
struct BrushPainter;
@@ -64,8 +66,11 @@ 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_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_break_stroke(BrushPainter *painter);
void brush_painter_free(BrushPainter *painter);
#endif
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 61d0b42d30d..6abe66be36b 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -299,7 +299,7 @@ void brush_check_exists(Brush **brush)
/* Brush Sampling */
-static float brush_sample_falloff(Brush *brush, float dist)
+float brush_sample_falloff(Brush *brush, float dist)
{
float a, outer, inner;
@@ -319,14 +319,9 @@ static float brush_sample_falloff(Brush *brush, float dist)
return 0.0f;
}
-void brush_sample(Brush *brush, float *xy, float dist, float *rgb, float *alpha, short texonly)
+void brush_sample_tex(Brush *brush, float *xy, float *rgba)
{
- if (alpha) {
- if (texonly) *alpha= 1.0;
- else *alpha= brush_sample_falloff(brush, dist);
- }
-
- if (xy && brush->mtex[0] && brush->mtex[0]->tex) {
+ if (brush->mtex[0] && brush->mtex[0]->tex) {
float co[3], tin, tr, tg, tb, ta;
int hasrgb;
@@ -336,81 +331,133 @@ void brush_sample(Brush *brush, float *xy, float dist, float *rgb, float *alpha,
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 (hasrgb) {
+ rgba[0]= tr;
+ rgba[1]= tg;
+ rgba[2]= tb;
+ rgba[3]= ta;
+ }
+ else {
+ rgba[0]= tin;
+ rgba[1]= tin;
+ rgba[2]= tin;
+ rgba[3]= 1.0f;
}
- if (alpha && hasrgb)
- *alpha *= ta;
}
- else if (rgb)
- VECCOPY(rgb, brush->rgb)
+ else if (rgba)
+ rgba[0]= rgba[1]= rgba[2]= rgba[3]= 1.0f;
}
#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)
+void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **outbuf)
{
ImBuf *ibuf;
- float w_2, h_2, xy[2], dist, rgba[3], *dstf;
- unsigned int x, y, rowbytes;
- char *dst;
+ float xy[2], dist, rgba[3], *dstf;
+ int x, y, rowbytes, xoff, yoff, imbflag;
+ char *dst, crgb[3];
- if (texonly && !(brush->mtex[0] && brush->mtex[0]->tex))
- return NULL;
-
- w_2 = size/2.0f;
- h_2 = size/2.0f;
+ imbflag= (flt)? IB_rectfloat: IB_rect;
+ xoff = -size/2.0f + 0.5f;
+ yoff = -size/2.0f + 0.5f;
rowbytes= size*4;
- if (flt) {
- ibuf= IMB_allocImBuf(size, size, 32, IB_rectfloat, 0);
+ if (*outbuf)
+ ibuf= *outbuf;
+ else
+ ibuf= IMB_allocImBuf(size, size, 32, imbflag, 0);
+ if (flt) {
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]);
+ xy[0] = x + xoff;
+ xy[1] = y + yoff;
+
+ if (texfall == 0) {
+ dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]);
- brush_sample(brush, xy, dist, dstf, dstf+3, texonly);
+ VECCOPY(dstf, brush->rgb);
+ dstf[3]= brush_sample_falloff(brush, dist);
+ }
+ else if (texfall == 1) {
+ brush_sample_tex(brush, xy, dstf);
+ }
+ else {
+ dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]);
+
+ brush_sample_tex(brush, xy, rgba);
+
+ dstf[0] = rgba[0]*brush->rgb[0];
+ dstf[1] = rgba[1]*brush->rgb[1];
+ dstf[2] = rgba[2]*brush->rgb[2];
+ dstf[3] = rgba[3]*brush_sample_falloff(brush, dist);
+ }
}
}
}
else {
- ibuf= IMB_allocImBuf(size, size, 32, IB_rect, 0);
+ crgb[0]= FTOCHAR(brush->rgb[0]);
+ crgb[1]= FTOCHAR(brush->rgb[1]);
+ crgb[2]= FTOCHAR(brush->rgb[2]);
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]);
+ xy[0] = x + xoff;
+ xy[1] = y + yoff;
+
+ if (texfall == 0) {
+ dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]);
+
+ dst[0]= crgb[0];
+ dst[1]= crgb[1];
+ dst[2]= crgb[2];
+ dst[3]= FTOCHAR(brush_sample_falloff(brush, dist));
+ }
+ else if (texfall == 1) {
+ brush_sample_tex(brush, xy, rgba);
+ dst[0]= FTOCHAR(rgba[0]);
+ dst[1]= FTOCHAR(rgba[1]);
+ dst[2]= FTOCHAR(rgba[2]);
+ dst[3]= FTOCHAR(rgba[3]);
+ }
+ else {
+ dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]);
+
+ brush_sample_tex(brush, xy, rgba);
+ dst[0] = FTOCHAR(rgba[0]*brush->rgb[0]);
+ dst[1] = FTOCHAR(rgba[1]*brush->rgb[1]);
+ dst[2] = FTOCHAR(rgba[2]*brush->rgb[2]);
+ dst[3] = FTOCHAR(rgba[3]*brush_sample_falloff(brush, dist));
+ }
}
}
}
- return ibuf;
+ *outbuf= ibuf;
}
/* Brush Painting */
+typedef struct BrushPainterCache {
+ short enabled;
+
+ 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 */
+
+ int lastsize;
+ float lastalpha;
+ float lastinnerradius;
+
+ ImBuf *ibuf;
+ ImBuf *texibuf;
+ ImBuf *maskibuf;
+} BrushPainterCache;
+
struct BrushPainter {
Brush *brush;
@@ -418,24 +465,14 @@ struct BrushPainter {
float accumdistance; /* accumulated distance of brush since last paint op */
float lastpaintpos[2]; /* position of last paint op */
+ float startpaintpos[2]; /* position of first paint */
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;
+ BrushPainterCache cache;
};
BrushPainter *brush_painter_new(Brush *brush)
@@ -444,42 +481,226 @@ BrushPainter *brush_painter_new(Brush *brush)
painter->brush= brush;
painter->firsttouch= 1;
+ painter->cache.lastsize= -1; /* force ibuf create in refresh */
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;
+ if ((painter->cache.flt != flt) || (painter->cache.size != size) ||
+ ((painter->cache.texonly != texonly) && texonly)) {
+ if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
+ if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf);
+ painter->cache.ibuf= painter->cache.maskibuf= NULL;
+ painter->cache.lastsize= -1; /* force ibuf create in refresh */
+ }
+
+ if (painter->cache.flt != flt) {
+ if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
+ painter->cache.texibuf= NULL;
+ painter->cache.lastsize= -1; /* force ibuf create in refresh */
+ }
+
+ 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);
+ if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
+ if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf);
MEM_freeN(painter);
}
-static void brush_painter_refresh_cache(BrushPainter *painter)
+static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, int x, int y, int w, int h, int xt, int yt, float *pos)
{
Brush *brush= painter->brush;
+ ImBuf *ibuf, *maskibuf, *texibuf;
+ float *bf, *mf, *tf, *otf=NULL, xoff, yoff, xy[2], rgba[4];
+ char *b, *m, *t, *ot= NULL;
+ int dotexold, origx= x, origy= y;
+
+ xoff = -brush->size/2.0f + 0.5f;
+ yoff = -brush->size/2.0f + 0.5f;
+ xoff += (int)pos[0] - (int)painter->startpaintpos[0];
+ yoff += (int)pos[1] - (int)painter->startpaintpos[1];
+
+ ibuf = painter->cache.ibuf;
+ texibuf = painter->cache.texibuf;
+ maskibuf = painter->cache.maskibuf;
+
+ dotexold = (oldtexibuf != NULL);
+
+ if (painter->cache.flt) {
+ for (; y < h; y++) {
+ bf = ibuf->rect_float + (y*ibuf->x + origx)*4;
+ tf = texibuf->rect_float + (y*texibuf->x + origx)*4;
+ mf = maskibuf->rect_float + (y*maskibuf->x + origx)*4;
+
+ if (dotexold)
+ otf = oldtexibuf->rect_float + ((y - origy + yt)*oldtexibuf->x + xt)*4;
+
+ for (x=origx; x < w; x++, bf+=4, mf+=4, tf+=4) {
+ if (dotexold) {
+ VECCOPY(tf, otf);
+ tf[3] = otf[3];
+ otf += 4;
+ }
+ else {
+ xy[0] = x + xoff;
+ xy[1] = y + yoff;
- if ((brush->size != painter->cache.lastsize)
- || (brush->alpha != painter->cache.lastalpha)
- || (brush->innerradius != painter->cache.lastinnerradius)) {
+ brush_sample_tex(brush, xy, tf);
+ }
- if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
+ bf[0] = tf[0]*mf[0];
+ bf[1] = tf[1]*mf[1];
+ bf[2] = tf[2]*mf[2];
+ bf[3] = tf[3]*mf[3];
+ }
+ }
+ }
+ else {
+ for (; y < h; y++) {
+ b = (char*)ibuf->rect + (y*ibuf->x + origx)*4;
+ t = (char*)texibuf->rect + (y*texibuf->x + origx)*4;
+ m = (char*)maskibuf->rect + (y*maskibuf->x + origx)*4;
+
+ if (dotexold)
+ ot = (char*)oldtexibuf->rect + ((y - origy + yt)*oldtexibuf->x + xt)*4;
+
+ for (x=origx; x < w; x++, b+=4, m+=4, t+=4) {
+ if (dotexold) {
+ t[0] = ot[0];
+ t[1] = ot[1];
+ t[2] = ot[2];
+ t[3] = ot[3];
+ ot += 4;
+ }
+ else {
+ xy[0] = x + xoff;
+ xy[1] = y + yoff;
+
+ brush_sample_tex(brush, xy, rgba);
+ t[0]= FTOCHAR(rgba[0]);
+ t[1]= FTOCHAR(rgba[1]);
+ t[2]= FTOCHAR(rgba[2]);
+ t[3]= FTOCHAR(rgba[3]);
+ }
- painter->cache.ibuf= brush_imbuf_new(brush,
- painter->cache.flt, painter->cache.texonly,
- painter->cache.size? painter->cache.size: brush->size);
+ b[0] = t[0]*m[0]/255;
+ b[1] = t[1]*m[1]/255;
+ b[2] = t[2]*m[2]/255;
+ b[3] = t[3]*m[3]/255;
+ }
+ }
+ }
+}
- painter->cache.lastsize= brush->size;
- painter->cache.lastalpha= brush->alpha;
- painter->cache.lastinnerradius= brush->innerradius;
+void brush_painter_fixed_tex_partial_update(BrushPainter *painter, float *pos)
+{
+ Brush *brush= painter->brush;
+ BrushPainterCache *cache= &painter->cache;
+ ImBuf *oldtexibuf, *ibuf;
+ int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
+
+ imbflag= (cache->flt)? IB_rectfloat: IB_rect;
+ if (!cache->ibuf)
+ cache->ibuf= IMB_allocImBuf(brush->size, brush->size, 32, imbflag, 0);
+ ibuf= cache->ibuf;
+
+ oldtexibuf= cache->texibuf;
+ cache->texibuf= IMB_allocImBuf(brush->size, brush->size, 32, imbflag, 0);
+
+ if (oldtexibuf) {
+ srcx= srcy= 0;
+ destx= (int)painter->lastpaintpos[0] - (int)pos[0];
+ desty= (int)painter->lastpaintpos[1] - (int)pos[1];
+ w= oldtexibuf->x;
+ h= oldtexibuf->y;
+
+ IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
}
+ else {
+ srcx= srcy= 0;
+ destx= desty= 0;
+ w= h= 0;
+ }
+
+ x1= destx;
+ y1= desty;
+ x2= destx+w;
+ y2= desty+h;
+
+ /* blend existing texture in new position */
+ if ((x1 < x2) && (y1 < y2))
+ brush_painter_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos);
+
+ if (oldtexibuf)
+ IMB_freeImBuf(oldtexibuf);
+
+ /* sample texture in new areas */
+ if ((0 < x1) && (0 < ibuf->y))
+ brush_painter_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos);
+ if ((x2 < ibuf->x) && (0 < ibuf->y))
+ brush_painter_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos);
+ if ((x1 < x2) && (0 < y1))
+ brush_painter_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos);
+ if ((x1 < x2) && (y2 < ibuf->y))
+ brush_painter_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos);
+}
+
+static void brush_painter_refresh_cache(BrushPainter *painter, float *pos)
+{
+ Brush *brush= painter->brush;
+ BrushPainterCache *cache= &painter->cache;
+ int size;
+ short flt;
+
+ if ((brush->size != cache->lastsize) || (brush->alpha != cache->lastalpha)
+ || (brush->innerradius != cache->lastinnerradius)) {
+ if (cache->ibuf) {
+ IMB_freeImBuf(cache->ibuf);
+ cache->ibuf= NULL;
+ }
+ if (cache->maskibuf) {
+ IMB_freeImBuf(cache->maskibuf);
+ cache->maskibuf= NULL;
+ }
+
+ flt= cache->flt;
+ size= (cache->size)? cache->size: brush->size;
+
+ if (!(brush->mtex[0] && brush->mtex[0]->tex) || (brush->mtex[0]->tex->type==0)) {
+ brush_imbuf_new(brush, flt, 0, size, &cache->ibuf);
+ }
+ else if (brush->flag & BRUSH_FIXED_TEX) {
+ brush_imbuf_new(brush, flt, 0, size, &cache->maskibuf);
+ brush_painter_fixed_tex_partial_update(painter, pos);
+ }
+ else
+ brush_imbuf_new(brush, flt, 2, size, &cache->ibuf);
+
+ cache->lastsize= brush->size;
+ cache->lastalpha= brush->alpha;
+ cache->lastinnerradius= brush->innerradius;
+ }
+ else if ((brush->flag & BRUSH_FIXED_TEX) && brush->mtex[0] && brush->mtex[0]->tex) {
+ int dx = (int)painter->lastpaintpos[0] - (int)pos[0];
+ int dy = (int)painter->lastpaintpos[1] - (int)pos[1];
+
+ if ((dx != 0) || (dy != 0))
+ brush_painter_fixed_tex_partial_update(painter, pos);
+ }
+}
+
+void brush_painter_break_stroke(BrushPainter *painter)
+{
+ painter->firsttouch= 1;
}
int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, void *user)
@@ -489,7 +710,11 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
if (painter->firsttouch) {
/* paint exactly once on first touch */
- if (painter->cache.enabled) brush_painter_refresh_cache(painter);
+ painter->startpaintpos[0]= pos[0];
+ painter->startpaintpos[1]= pos[1];
+
+ if (painter->cache.enabled)
+ brush_painter_refresh_cache(painter, pos);
totpaintops += func(user, painter->cache.ibuf, pos, pos);
painter->lastpaintpos[0]= pos[0];
@@ -547,8 +772,10 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
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);
+ if (painter->cache.enabled)
+ brush_painter_refresh_cache(painter, paintpos);
+ totpaintops +=
+ func(user, painter->cache.ibuf, painter->lastpaintpos, paintpos);
painter->lastpaintpos[0]= paintpos[0];
painter->lastpaintpos[1]= paintpos[1];
@@ -570,8 +797,10 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
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);
+ if (painter->cache.enabled)
+ brush_painter_refresh_cache(painter, paintpos);
+ totpaintops +=
+ func(user, painter->cache.ibuf, painter->lastmousepos, pos);
painter->accumtime -= brush->rate;
}
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 59fcd3e25e2..b56c0df0105 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -250,23 +250,23 @@ void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
if (dbuf == NULL) return;
if (*destx < 0) {
- *srcx -= *destx ;
- *width += *destx ;
+ *srcx -= *destx;
+ *width += *destx;
*destx = 0;
}
if (*srcx < 0) {
- *destx -= *srcx ;
- *width += *destx ;
+ *destx -= *srcx;
+ *width += *destx;
*srcx = 0;
}
if (*desty < 0) {
- *srcy -= *desty ;
- *height += *desty ;
+ *srcy -= *desty;
+ *height += *desty;
*desty = 0;
}
if (*srcy < 0) {
- *desty -= *srcy ;
- *height += *desty ;
+ *desty -= *srcy;
+ *height += *desty;
*srcy = 0;
}
@@ -281,6 +281,11 @@ void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
tmp = sbuf->y - *srcy;
if (*height > tmp) *height = tmp;
}
+
+ if ((*height <= 0) || (*width <= 0)) {
+ *width = 0;
+ *height = 0;
+ }
}
/* copy and blend */
diff --git a/source/blender/include/BDR_drawmesh.h b/source/blender/include/BDR_drawmesh.h
index 7463cffa6ef..b2b68b25d60 100644
--- a/source/blender/include/BDR_drawmesh.h
+++ b/source/blender/include/BDR_drawmesh.h
@@ -70,6 +70,8 @@ int get_linear_mipmap(void);
*/
void clear_realtime_image_cache(void);
+
+void update_realtime_image(struct Image *ima, int x, int y, int w, int h);
void free_realtime_image(struct Image *ima);
void free_all_realtime_images(void);
void make_repbind(struct Image *ima);
diff --git a/source/blender/include/BDR_imagepaint.h b/source/blender/include/BDR_imagepaint.h
index 9ea9c9a107a..e687d220906 100644
--- a/source/blender/include/BDR_imagepaint.h
+++ b/source/blender/include/BDR_imagepaint.h
@@ -35,9 +35,10 @@
void imagepaint_redraw_tool(void);
void imagepaint_pick(short mousebutton);
+void imagepaint_paint(short mousebutton, short texturepaint);
-void imagepaint_paint(short mousebutton);
-void texturepaint_paint(short mousebutton);
+void imagepaint_undo();
+void free_imagepaint();
#endif /* BDR_IMAGEPAINT_H */
diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h
index 63a5face413..a73c92cc2f5 100644
--- a/source/blender/include/butspace.h
+++ b/source/blender/include/butspace.h
@@ -544,6 +544,7 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la
#define B_BRUSHLOCAL 2853
#define B_BRUSHCHANGE 2854
#define B_BTEXBROWSE 2855
+#define B_BTEXDELETE 2856
/* *********************** */
#define B_RADIOBUTS 3000
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 1d620de8979..a57b3d3d687 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -64,6 +64,7 @@ typedef struct Brush {
/* Brush.flag */
#define BRUSH_AIRBRUSH 1
#define BRUSH_TORUS 2
+#define BRUSH_FIXED_TEX 4
/* Brush.blend */
#define BRUSH_BLEND_MIX 0
diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c
index baa3d27be90..c3e45f49123 100644
--- a/source/blender/src/buttons_editing.c
+++ b/source/blender/src/buttons_editing.c
@@ -3904,26 +3904,42 @@ 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;
+ if(settings->imapaint.brush) {
+ Brush *brush= settings->imapaint.brush;
+
+ if(G.buts->menunr==-2) {
+ MTex *mtex= brush->mtex[brush->texact];
+ 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(brush, G.buts->menunr)) {
+ BIF_undo_push("Browse Brush Texture");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
}
- 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;
+ case B_BTEXDELETE:
+ 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;
+ case B_BRUSHCHANGE:
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
}
}
-
/* -------------------- MODE: vpaint ------------------- */
static void editing_panel_mesh_paint(void)
@@ -3986,7 +4002,7 @@ static void editing_panel_mesh_paint(void)
uiBlockEndAlign(block);
}
}
- else { // if(G.f & G_VERTEXPAINT) {
+ else if(G.f & G_VERTEXPAINT) {
extern VPaint Gvp; /* from vpaint */
uiBlockBeginAlign(block);
@@ -4025,7 +4041,6 @@ static void editing_panel_mesh_paint(void)
uiDefButF(block, NUM, B_DIFF, "Gamma:", 1174,0,102,19, &Gvp.gamma, 0.1, 5.0, 10, 0, "Change the clarity of the vertex colors");
uiBlockEndAlign(block);
}
-#if 0
else { /* texture paint */
ToolSettings *settings= G.scene->toolsettings;
Brush *brush= settings->imapaint.brush;
@@ -4035,9 +4050,9 @@ static void editing_panel_mesh_paint(void)
yco= 160;
uiBlockBeginAlign(block);
- uiDefButS(block, ROW, B_BRUSHCHANGE, "Draw", 0 ,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_DRAW, 0, 0, "Draw brush");
- uiDefButS(block, ROW, B_BRUSHCHANGE, "Soften", 80 ,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SOFTEN, 0, 0, "Soften brush");
- uiDefButS(block, ROW, B_BRUSHCHANGE, "Smear", 160,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SMEAR, 0, 0, "Smear brush");
+ uiDefButS(block, ROW, B_BRUSHCHANGE, "Draw", 0 ,yco,108,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_DRAW, 0, 0, "Draw brush");
+ uiDefButS(block, ROW, B_BRUSHCHANGE, "Soften", 108 ,yco,106,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SOFTEN, 0, 0, "Soften brush");
+ uiDefButS(block, ROW, B_BRUSHCHANGE, "Smear", 214,yco,106,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SMEAR, 0, 0, "Smear brush");
uiBlockEndAlign(block);
yco -= 30;
@@ -4049,13 +4064,13 @@ static void editing_panel_mesh_paint(void)
if(brush && !brush->id.lib) {
butw= 320-(xco+10);
- uiDefButS(block, MENU, B_SIMANOTHING, "Mix %x0|Add %x1|Subtract %x2|Multiply %x3|Lighten %x4|Darken %x5", xco+10,yco,butw,19, &brush->blend, 0, 0, 0, 0, "Blending method for applying brushes");
+ uiDefButS(block, MENU, B_NOP, "Mix %x0|Add %x1|Subtract %x2|Multiply %x3|Lighten %x4|Darken %x5", xco+10,yco,butw,19, &brush->blend, 0, 0, 0, 0, "Blending method for applying brushes");
- uiDefButBitS(block, TOG|BIT, BRUSH_TORUS, B_SIMABRUSHCHANGE, "Wrap", xco+10,yco-25,butw,19, &brush->flag, 0, 0, 0, 0, "Enables torus wrapping");
+ uiDefButBitS(block, TOG|BIT, BRUSH_TORUS, B_BRUSHCHANGE, "Wrap", xco+10,yco-25,butw,19, &brush->flag, 0, 0, 0, 0, "Enables torus wrapping");
uiBlockBeginAlign(block);
- uiDefButBitS(block, TOG|BIT, BRUSH_AIRBRUSH, B_SIMABRUSHCHANGE, "Airbrush", xco+10,yco-50,butw,19, &brush->flag, 0, 0, 0, 0, "Keep applying paint effect while holding mouse (spray)");
- uiDefButF(block, NUM, B_SIMANOTHING, "Rate ", xco+10,yco-70,butw,19, &brush->rate, 0.01, 1.0, 0, 0, "Number of paints per second for Airbrush");
+ uiDefButBitS(block, TOG|BIT, BRUSH_AIRBRUSH, B_BRUSHCHANGE, "Airbrush", xco+10,yco-50,butw,19, &brush->flag, 0, 0, 0, 0, "Keep applying paint effect while holding mouse (spray)");
+ uiDefButF(block, NUM, B_NOP, "Rate ", xco+10,yco-70,butw,19, &brush->rate, 0.01, 1.0, 0, 0, "Number of paints per second for Airbrush");
uiBlockEndAlign(block);
yco -= 25;
@@ -4065,15 +4080,18 @@ static void editing_panel_mesh_paint(void)
uiDefButF(block, NUMSLI, B_NOP, "Opacity ", 0,yco-20,200,19, &brush->alpha, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
uiDefButI(block, NUMSLI, B_NOP, "Size ", 0,yco-40,200,19, &brush->size, 1, 200, 0, 0, "The size of the brush");
uiDefButF(block, NUMSLI, B_NOP, "Falloff ", 0,yco-60,200,19, &brush->innerradius, 0.0, 1.0, 0, 0, "The fall off radius of the brush");
-
- if(brush->flag & BRUSH_AIRBRUSH)
- uiDefButF(block, NUMSLI, B_NOP, "Flow ", 0,yco-80,200,19, &brush->spacing, 1.0, 100.0, 0, 0, "Paint Flow for Air Brush");
- else
- uiDefButF(block, NUMSLI, B_NOP, "Stepsize ",0,yco-80,200,19, &brush->spacing, 1.0, 100.0, 0, 0, "Repeating Paint On %% of Brush diameter");
+ uiDefButF(block, NUMSLI, B_NOP, "Spacing ",0,yco-80,200,19, &brush->spacing, 1.0, 100.0, 0, 0, "Repeating paint on %% of brush diameter");
uiBlockEndAlign(block);
+
+ yco -= 110;
+
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ id= (brush->mtex[0])? (ID*)brush->mtex[0]->tex: NULL;
+ xco= std_libbuttons(block, 0, yco, 0, NULL, B_BTEXBROWSE, ID_TE, 0, id, NULL, &(G.buts->menunr), 0, 0, B_BTEXDELETE, 0, 0);
+ /*uiDefButBitS(block, TOG|BIT, BRUSH_FIXED_TEX, B_BRUSHCHANGE, "Fixed", xco+5,yco,butw,19, &brush->flag, 0, 0, 0, 0, "Keep texture origin in fixed position");*/
+ uiBlockSetCol(block, TH_AUTO);
}
}
-#endif
}
static void editing_panel_mesh_texface(void)
diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c
index 00c96389ac5..8f2d14a3d78 100644
--- a/source/blender/src/buttons_shading.c
+++ b/source/blender/src/buttons_shading.c
@@ -1251,7 +1251,7 @@ static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *l
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);
+ std_libbuttons(block, 10, 180, 0, NULL, B_BTEXBROWSE, ID_TE, 0, id, idfrom, &(G.buts->menunr), B_TEXALONE, B_TEXLOCAL, B_TEXDELETE, B_AUTOTEXNAME, B_KEEPDATA);
}
else if(node) {
diff --git a/source/blender/src/drawimage.c b/source/blender/src/drawimage.c
index 0d1aba9438a..ce6a4e63fcd 100644
--- a/source/blender/src/drawimage.c
+++ b/source/blender/src/drawimage.c
@@ -1097,6 +1097,7 @@ static void image_panel_paint(short cntrl) // IMAGE_HANDLER_PROPERTIES
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);
+ /*uiDefButBitS(block, TOG|BIT, BRUSH_FIXED_TEX, B_SIMABRUSHCHANGE, "Fixed", xco+5,yco,butw,19, &brush->flag, 0, 0, 0, 0, "Keep texture origin in fixed position");*/
uiBlockSetCol(block, TH_AUTO);
}
}
diff --git a/source/blender/src/drawmesh.c b/source/blender/src/drawmesh.c
index 2ff671d33fa..d3556f82243 100644
--- a/source/blender/src/drawmesh.c
+++ b/source/blender/src/drawmesh.c
@@ -430,6 +430,34 @@ int set_tpage(TFace *tface)
return 1;
}
+void update_realtime_image(Image *ima, int x, int y, int w, int h)
+{
+ if (ima->repbind || fDoMipMap || !ima->bindcode || !ima->ibuf ||
+ (!is_pow2(ima->ibuf->x) || !is_pow2(ima->ibuf->y)) ||
+ (w == 0) || (h == 0)) {
+ /* these special cases require full reload still */
+ free_realtime_image(ima);
+ }
+ else {
+ int row_length = glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
+ int skip_pixels = glaGetOneInteger(GL_UNPACK_SKIP_PIXELS);
+ int skip_rows = glaGetOneInteger(GL_UNPACK_SKIP_ROWS);
+
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode);
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, ima->ibuf->x);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
+ GL_UNSIGNED_BYTE, ima->ibuf->rect);
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows);
+ }
+}
+
void free_realtime_image(Image *ima)
{
if(ima->bindcode) {
diff --git a/source/blender/src/drawview.c b/source/blender/src/drawview.c
index b81631601d0..751d7f6e791 100644
--- a/source/blender/src/drawview.c
+++ b/source/blender/src/drawview.c
@@ -53,6 +53,7 @@
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
@@ -2253,7 +2254,15 @@ static void view3d_panel_object(short cntrl) // VIEW3D_HANDLER_OBJECT
else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT)) {
extern VPaint Gvp; /* from vpaint */
static float hsv[3], old[3]; // used as temp mem for picker
- uiBlockPickerButtons(block, &Gvp.r, hsv, old, hexcol, 'f', REDRAWBUTSEDIT); /* 'f' is for floating panel */
+ float *rgb= NULL;
+ ToolSettings *settings= G.scene->toolsettings;
+
+ if(G.f & G_VERTEXPAINT) rgb= &Gvp.r;
+ else if(settings->imapaint.brush) rgb= settings->imapaint.brush->rgb;
+
+ if (rgb)
+ /* 'f' is for floating panel */
+ uiBlockPickerButtons(block, rgb, hsv, old, hexcol, 'f', REDRAWBUTSEDIT);
}
else {
BoundBox *bb = NULL;
diff --git a/source/blender/src/editface.c b/source/blender/src/editface.c
index b97b89cbe5a..6a671a0da93 100644
--- a/source/blender/src/editface.c
+++ b/source/blender/src/editface.c
@@ -1575,7 +1575,7 @@ void texpaint_pick_uv(Object *ob, Mesh *mesh, TFace *tf, short *xy, float *uv)
if (nvert == 4) {
texpaint_barycentric_2d(v1, v2, v4, p, w);
-
+
if(w[0] < 0.0f) {
/* if w[0] is negative, co is on the other side of the v1-v3 edge,
so we interpolate using the other triangle */
diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c
index a0aa801b55a..9a3b41870ba 100644
--- a/source/blender/src/header_view3d.c
+++ b/source/blender/src/header_view3d.c
@@ -86,6 +86,7 @@
#include "BDR_editface.h"
#include "BDR_editmball.h"
#include "BDR_editobject.h"
+#include "BDR_imagepaint.h"
#include "BDR_vpaint.h"
#include "BIF_editlattice.h"
@@ -3761,6 +3762,12 @@ static uiBlock *view3d_vpaintmenu(void *arg_unused)
/* texture paint menu (placeholder, no items yet??) */
static void do_view3d_tpaintmenu(void *arg, int event)
{
+ switch(event) {
+ case 0: /* undo image painting */
+ imagepaint_undo();
+ break;
+ }
+
allqueue(REDRAWVIEW3D, 0);
}
@@ -3772,6 +3779,7 @@ static uiBlock *view3d_tpaintmenu(void *arg_unused)
block= uiNewBlock(&curarea->uiblocks, "view3d_paintmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
uiBlockSetButmFunc(block, do_view3d_tpaintmenu, NULL);
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Undo Texture Painting|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
if(curarea->headertype==HEADERTOP) {
diff --git a/source/blender/src/imagepaint.c b/source/blender/src/imagepaint.c
index f80d5a6723d..1e372c3ec28 100644
--- a/source/blender/src/imagepaint.c
+++ b/source/blender/src/imagepaint.c
@@ -85,7 +85,7 @@
#include "blendef.h"
#include "mydevice.h"
-/* ImagePaint Utilities */
+/* Defines and Structs */
#define IMAPAINT_FLOAT_TO_CHAR(f) ((char)(f*255))
#define IMAPAINT_CHAR_TO_FLOAT(c) (c/255.0f)
@@ -96,30 +96,191 @@
f[1]=IMAPAINT_CHAR_TO_FLOAT(c[1]); f[2]=IMAPAINT_CHAR_TO_FLOAT(c[2]); }
#define IMAPAINT_FLOAT_RGB_COPY(a, b) VECCOPY(a, b)
-static void imapaint_blend_line(ImBuf *ibuf, ImBuf *ibufb, float *start, float *end)
+#define IMAPAINT_TILE_BITS 6
+#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS)
+#define IMAPAINT_TILE_NUMBER(size) (((size)+IMAPAINT_TILE_SIZE-1) >> IMAPAINT_TILE_BITS)
+
+typedef struct ImagePaintState {
+ Brush *brush;
+ short tool;
+ Image *image;
+ ImBuf *canvas;
+ ImBuf *clonecanvas;
+ short clonefreefloat;
+ char *warnpackedfile;
+
+ /* texture paint only */
+ Object *ob;
+ Mesh *me;
+ TFace *tface;
+ float uv[2];
+} ImagePaintState;
+
+typedef struct ImagePaintUndo {
+ Image *image;
+ ImBuf *tilebuf;
+ void **tiles;
+ int xtiles, ytiles;
+} ImagePaintUndo;
+
+typedef struct ImagePaintPartialRedraw {
+ int x1, y1, x2, y2;
+ int enabled;
+} ImagePaintPartialRedraw;
+
+static ImagePaintUndo imapaintundo = {NULL, NULL, NULL, 0, 0};
+static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
+
+static void init_imagapaint_undo(Image *ima)
+{
+ int xt, yt;
+
+ imapaintundo.image = ima;
+ imapaintundo.xtiles = xt = IMAPAINT_TILE_NUMBER(ima->ibuf->x);
+ imapaintundo.ytiles = yt = IMAPAINT_TILE_NUMBER(ima->ibuf->y);
+ imapaintundo.tiles = MEM_callocN(sizeof(void*)*xt*yt, "ImagePaintUndoTiles");
+ imapaintundo.tilebuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE,
+ ima->ibuf->depth, (ima->ibuf->rect_float)? IB_rectfloat: IB_rect, 0);
+}
+
+static void imapaint_copy_tile(Image *ima, int tile, int x, int y, int swapundo)
+{
+ IMB_rectcpy(imapaintundo.tilebuf, ima->ibuf, 0, 0, x*IMAPAINT_TILE_SIZE,
+ y*IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+
+ if (imapaintundo.tilebuf->rect_float)
+ SWAP(void*, imapaintundo.tilebuf->rect_float, imapaintundo.tiles[tile])
+ else
+ SWAP(void*, imapaintundo.tilebuf->rect, imapaintundo.tiles[tile])
+
+ if (swapundo)
+ IMB_rectcpy(ima->ibuf, imapaintundo.tilebuf, x*IMAPAINT_TILE_SIZE,
+ y*IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+}
+
+static void imapaint_clear_partial_redraw()
+{
+ memset(&imapaintpartial, 0, sizeof(imapaintpartial));
+}
+
+static void imapaint_dirty_region(Image *ima, int x, int y, int w, int h)
+{
+ int srcx= 0, srcy= 0, origx, tile, allocsize;
+
+ IMB_rectclip(ima->ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
+
+ if (w == 0 || h == 0)
+ return;
+
+ if (!imapaintpartial.enabled) {
+ imapaintpartial.x1 = x;
+ imapaintpartial.y1 = y;
+ imapaintpartial.x2 = x+w;
+ imapaintpartial.y2 = y+h;
+ imapaintpartial.enabled = 1;
+ }
+ else {
+ imapaintpartial.x1 = MIN2(imapaintpartial.x1, x);
+ imapaintpartial.y1 = MIN2(imapaintpartial.y1, y);
+ imapaintpartial.x2 = MAX2(imapaintpartial.x2, x+w);
+ imapaintpartial.y2 = MAX2(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++) {
+ if (ima != imapaintundo.image) {
+ free_imagepaint();
+ init_imagapaint_undo(ima);
+ }
+
+ tile = y*imapaintundo.xtiles + x;
+ if (!imapaintundo.tiles[tile]) {
+ allocsize= (ima->ibuf->rect_float)? sizeof(float): sizeof(char);
+ imapaintundo.tiles[tile]= MEM_mapallocN(allocsize*4*
+ IMAPAINT_TILE_SIZE*IMAPAINT_TILE_SIZE, "ImagePaintUndoTile");
+ imapaint_copy_tile(ima, tile, x, y, 0);
+ }
+ }
+ }
+
+ ima->ibuf->userflags |= IB_BITMAPDIRTY;
+}
+
+static void imapaint_image_update(Image *image, short texpaint)
+{
+ if(image->ibuf->rect_float)
+ imb_freerectImBuf(image->ibuf); /* force recreate of char rect */
+
+ /* todo: should set_tpage create ->rect? */
+ if(texpaint || G.sima->lock) {
+ int w = imapaintpartial.x2 - imapaintpartial.x1;
+ int h = imapaintpartial.y2 - imapaintpartial.y1;
+ update_realtime_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h);
+ }
+}
+
+static void imapaint_redraw(int final, int texpaint, Image *image)
+{
+ if(final) {
+ if(texpaint)
+ allqueue(REDRAWIMAGE, 0);
+ else if(!G.sima->lock) {
+ if(image)
+ free_realtime_image(image); /* force OpenGL reload */
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ allqueue(REDRAWHEADERS, 0);
+ }
+ else if(!texpaint && G.sima->lock)
+ force_draw_plus(SPACE_VIEW3D, 0);
+ else
+ force_draw(0);
+}
+
+void imagepaint_undo()
{
- float numsteps, t, pos[2];
- int step, d[2], ipos[2];
+ int x, y, tile;
+ Image *ima= imapaintundo.image;
- 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);
+ if (!ima || !ima->ibuf || !(ima->ibuf->rect || ima->ibuf->rect_float))
+ return;
- if(numsteps < 1.0)
- numsteps = 1.0f;
+ for (tile = 0, y = 0; y < imapaintundo.ytiles; y++)
+ for (x = 0; x < imapaintundo.xtiles; x++, tile++)
+ if (imapaintundo.tiles[tile])
+ imapaint_copy_tile(ima, tile, x, y, 1);
- for (step=0; step < numsteps; step++) {
- t = (step+1)/numsteps;
- pos[0] = start[0] + d[0]*t;
- pos[1] = start[1] + d[1]*t;
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
- 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);
+ free_realtime_image(ima); /* force OpenGL reload */
+}
+
+void free_imagepaint()
+{
+ /* todo: does this need to be in the same places as editmode_undo_clear,
+ vertex paint isn't? */
+ int i, size = imapaintundo.xtiles*imapaintundo.ytiles;
+
+ if (imapaintundo.tiles) {
+ for (i = 0; i < size; i++)
+ if (imapaintundo.tiles[i])
+ MEM_freeN(imapaintundo.tiles[i]);
+ MEM_freeN(imapaintundo.tiles);
}
+ if (imapaintundo.tilebuf)
+ IMB_freeImBuf(imapaintundo.tilebuf);
+
+ memset(&imapaintundo, 0, sizeof(imapaintundo));
}
+/* Image Paint Operations */
+
static void imapaint_ibuf_get_set_rgb(ImBuf *ibuf, int x, int y, short torus, short set, float *rgb)
{
if (torus) {
@@ -160,8 +321,6 @@ static int imapaint_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, flo
return 1;
}
-/* ImagePaint Tools */
-
static void imapaint_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, short torus)
{
int x, y, count, xi, yi, xo, yo;
@@ -236,15 +395,6 @@ static ImBuf *imapaint_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
return clonebuf;
}
-/* ImagePaint state and operations */
-
-typedef struct ImagePaintState {
- Brush *brush;
- short tool;
- ImBuf *canvas;
- ImBuf *clonecanvas;
-} ImagePaintState;
-
static void imapaint_convert_brushco(ImBuf *ibufb, float *pos, int *ipos)
{
ipos[0]= (int)(pos[0] - ibufb->x/2);
@@ -253,43 +403,45 @@ static void imapaint_convert_brushco(ImBuf *ibufb, float *pos, int *ipos)
static int imapaint_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *pos)
{
- ImagePaintState s= *((ImagePaintState*)state);
+ 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;
+ 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 ((s.tool == PAINT_TOOL_SMEAR) && (lastpos[0]==pos[0]) && (lastpos[1]==pos[1]))
- return 0;
-
imapaint_convert_brushco(ibufb, pos, bpos);
/* lift from canvas */
- if(s.tool == PAINT_TOOL_SOFTEN) {
- imapaint_lift_soften(s.canvas, ibufb, bpos, torus);
+ if(s->tool == PAINT_TOOL_SOFTEN) {
+ imapaint_lift_soften(s->canvas, ibufb, bpos, torus);
}
- else if(s.tool == PAINT_TOOL_SMEAR) {
+ else if(s->tool == PAINT_TOOL_SMEAR) {
+ if (lastpos[0]==pos[0] && lastpos[1]==pos[1])
+ return 0;
+
imapaint_convert_brushco(ibufb, lastpos, blastpos);
- imapaint_lift_smear(s.canvas, ibufb, 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;
+ 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;
imapaint_convert_brushco(ibufb, liftpos, bliftpos);
- clonebuf= imapaint_lift_clone(s.clonecanvas, ibufb, bliftpos);
+ clonebuf= imapaint_lift_clone(s->clonecanvas, ibufb, bliftpos);
}
+ imapaint_dirty_region(s->image, bpos[0], bpos[1], ibufb->x, ibufb->y);
+
/* blend into canvas */
if(torus)
- IMB_rectblend_torus(s.canvas, (clonebuf)? clonebuf: ibufb,
+ 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,
+ 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;
@@ -302,299 +454,230 @@ static void imapaint_compute_uvco(short *mval, float *uv)
areamouseco_to_ipoco(G.v2d, mval, &uv[0], &uv[1]);
}
-static void imapaint_compute_imageco(ImBuf *ibuf, short *mval, float *mousepos)
-{
- areamouseco_to_ipoco(G.v2d, mval, &mousepos[0], &mousepos[1]);
- mousepos[0] *= ibuf->x;
- mousepos[1] *= ibuf->y;
-}
+/* 3D TexturePaint */
-void imapaint_redraw_tool(void)
-{
- if(G.scene->toolsettings->imapaint.flag & IMAGEPAINT_DRAW_TOOL_DRAWING)
- force_draw(0);
-}
+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 imapaint_redraw(int final, int painted)
+static int texpaint_break_stroke(float *prevuv, float *fwuv, float *bkuv, float *uv)
{
- if(!final && !painted) {
- imapaint_redraw_tool();
- return;
- }
+ float d1[2], d2[2];
+ float mismatch = Vec2Lenf(fwuv, uv);
+ float len1 = Vec2Lenf(prevuv, fwuv);
+ float len2 = Vec2Lenf(bkuv, uv);
- if(final || painted) {
- if (final || G.sima->lock) {
- /* Make OpenGL aware of a changed texture */
- free_realtime_image(G.sima->image);
- force_draw_plus(SPACE_VIEW3D,0);
- }
- else
- force_draw(0);
- }
+ Vec2Subf(d1, fwuv, prevuv);
+ Vec2Subf(d2, uv, bkuv);
- if(final)
- allqueue(REDRAWHEADERS, 0);
+ return ((Inp2f(d1, d2) < 0.0f) || (mismatch > MAX2(len1, len2)*2));
}
-static int imapaint_canvas_init(Brush *brush, short tool, ImBuf **canvas, ImBuf **clonecanvas, short *freefloat)
-{
- Image *ima= G.sima->image;
+/* ImagePaint Common */
- /* verify that we can paint and create canvas */
- if(!ima || !ima->ibuf || !(ima->ibuf->rect || ima->ibuf->rect_float))
+static int imapaint_canvas_set(ImagePaintState *s, Image *ima)
+{
+ /* verify that we can paint and set canvas */
+ if(ima->packedfile) {
+ s->warnpackedfile = ima->id.name + 2;
+ return 0;
+ }
+ else if(!ima || !ima->ibuf || !(ima->ibuf->rect || ima->ibuf->rect_float))
return 0;
else if(ima->packedfile)
return 0;
- *canvas= ima->ibuf;
+ s->image= ima;
+ s->canvas= ima->ibuf;
- /* create clone canvas */
- if(clonecanvas && (tool == PAINT_TOOL_CLONE)) {
- ima= brush->clone.image;
+ /* set clone canvas */
+ if(s->tool == PAINT_TOOL_CLONE) {
+ ima= s->brush->clone.image;
if(!ima || !ima->ibuf || !(ima->ibuf->rect || ima->ibuf->rect_float))
return 0;
- *clonecanvas= ima->ibuf;
+ s->clonecanvas= ima->ibuf;
- if((*canvas)->rect_float && !(*clonecanvas)->rect_float) {
+ if(s->canvas->rect_float && !s->clonecanvas->rect_float) {
/* temporarily add float rect for cloning */
- *freefloat= 1;
- IMB_float_from_rect(*clonecanvas);
+ IMB_float_from_rect(s->clonecanvas);
+ s->clonefreefloat= 1;
}
- else if(!(*canvas)->rect_float && !(*clonecanvas)->rect) {
- *freefloat= 0;
- IMB_rect_from_float(*clonecanvas);
+ else if(!s->canvas->rect_float && !s->clonecanvas->rect)
+ IMB_rect_from_float(s->clonecanvas);
+ }
+
+ return 1;
+}
+
+static void imapaint_canvas_free(ImagePaintState *s)
+{
+ if (s->clonefreefloat)
+ imb_freerectfloatImBuf(s->clonecanvas);
+}
+
+static int imapaint_do_paint(ImagePaintState *s, BrushPainter *painter, Image *image, short texpaint, float *uv, double time, int update)
+{
+ float pos[2];
+
+ pos[0] = uv[0]*image->ibuf->x;
+ pos[1] = uv[1]*image->ibuf->y;
+
+ brush_painter_require_imbuf(painter, ((image->ibuf->rect_float)? 1: 0), 0, 0);
+
+ if (brush_painter_paint(painter, imapaint_paint_op, pos, time, s)) {
+ if (update)
+ imapaint_image_update(image, texpaint);
+ return 1;
+ }
+ else return 0;
+}
+
+static void imapaint_do(ImagePaintState *s, BrushPainter *painter, short texpaint, short *prevmval, short *mval, double time)
+{
+ TFace *newtface = NULL;
+ Image *newimage = NULL;
+ float fwuv[2], bkuv[2], newuv[2];
+ unsigned int face_index;
+ int breakstroke = 0, redraw = 0;
+
+ if (texpaint) {
+
+ /* pick face and image */
+ if (facesel_face_pick(s->me, mval, &face_index, 0)) {
+ newtface = s->me->tface + face_index;
+ newimage = (Image*)newtface->tpage;
+ texpaint_pick_uv(s->ob, s->me, newtface, mval, newuv);
}
else
- *freefloat= 0;
+ newuv[0] = newuv[1] = 0.0f;
+
+ /* see if stroke is broken, and if so finish painting in old position */
+ if (s->image) {
+ if (newimage == s->image) {
+ texpaint_pick_uv(s->ob, s->me, s->tface, mval, fwuv);
+ texpaint_pick_uv(s->ob, s->me, newtface, prevmval, bkuv);
+ breakstroke= texpaint_break_stroke(s->uv, fwuv, bkuv, newuv);
+ }
+ else
+ breakstroke= 1;
+ }
+
+ if (breakstroke) {
+ texpaint_pick_uv(s->ob, s->me, s->tface, mval, fwuv);
+ redraw |= imapaint_do_paint(s, painter, s->image, texpaint, fwuv, time, 1);
+ imapaint_clear_partial_redraw();
+ brush_painter_break_stroke(painter);
+ }
+
+ /* set new canvas */
+ if (newimage && (newimage != s->image))
+ if (!imapaint_canvas_set(s, newimage))
+ newimage = NULL;
+
+ /* paint in new image */
+ if (newimage) {
+ if (breakstroke)
+ redraw|= imapaint_do_paint(s, painter, newimage, texpaint, bkuv, time, 0);
+ redraw|= imapaint_do_paint(s, painter, newimage, texpaint, newuv, time, 1);
+ }
+
+ /* update state */
+ s->image = newimage;
+ s->tface = newtface;
+ s->uv[0] = newuv[0];
+ s->uv[1] = newuv[1];
+ }
+ else {
+ imapaint_compute_uvco(mval, newuv);
+ redraw |= imapaint_do_paint(s, painter, s->image, texpaint, newuv, time, 1);
}
- else if(clonecanvas)
- *clonecanvas= NULL;
- return 1;
+ if (redraw) {
+ imapaint_redraw(0, texpaint, NULL);
+ imapaint_clear_partial_redraw();
+ }
}
-void imagepaint_paint(short mousebutton)
+void imagepaint_paint(short mousebutton, short texpaint)
{
ImagePaintState s;
BrushPainter *painter;
ToolSettings *settings= G.scene->toolsettings;
- short prevmval[2], mval[2], freefloat=0;
- float mousepos[2];
- double mousetime;
+ short prevmval[2], mval[2];
+ double time;
/* initialize state */
+ memset(&s, 0, sizeof(s));
s.brush= settings->imapaint.brush;
s.tool= settings->imapaint.tool;
+ if(texpaint && (s.tool == PAINT_TOOL_CLONE))
+ s.tool = PAINT_TOOL_DRAW;
- 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");
+ if(!s.brush)
return;
+
+ if(texpaint) {
+ s.ob = OBACT;
+ if (!s.ob || !(s.ob->lay & G.vd->lay)) return;
+ s.me = get_mesh(s.ob);
+ if (!s.me) return;
+
+ persp(PERSP_VIEW);
+ }
+ else {
+ s.image = G.sima->image;
+
+ if(!imapaint_canvas_set(&s, G.sima->image)) {
+ if(s.warnpackedfile)
+ error("Painting in packed images not supported");
+ return;
+ }
}
settings->imapaint.flag |= IMAGEPAINT_DRAWING;
+ free_imagepaint();
/* 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();
+ time= PIL_check_seconds_timer();
prevmval[0]= mval[0];
prevmval[1]= mval[1];
- imapaint_compute_imageco(s.canvas, mval, mousepos);
- 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);
- }
+ imapaint_do(&s, painter, texpaint, prevmval, mval, time);
/* paint loop */
while(get_mbut() & mousebutton) {
getmouseco_areawin(mval);
- mousetime= PIL_check_seconds_timer();
+ time= PIL_check_seconds_timer();
if((mval[0] != prevmval[0]) || (mval[1] != prevmval[1])) {
+ imapaint_do(&s, painter, texpaint, prevmval, mval, time);
prevmval[0]= mval[0];
prevmval[1]= mval[1];
- imapaint_compute_imageco(s.canvas, mval, mousepos);
}
- else if (!(s.brush->flag & BRUSH_AIRBRUSH))
- continue;
-
- 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);
- }
-
- /* todo: check if we can wait here to not take up all cpu usage? */
+ else if (s.brush->flag & BRUSH_AIRBRUSH)
+ imapaint_do(&s, painter, texpaint, prevmval, mval, time);
+ else
+ BIF_wait_for_statechange();
}
/* clean up */
settings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
- s.canvas->userflags |= IB_BITMAPDIRTY;
-
- if (freefloat) imb_freerectfloatImBuf(s.clonecanvas);
-
+ imapaint_canvas_free(&s);
brush_painter_free(painter);
- imapaint_redraw(1, 0);
-}
-
-/* 3D TexturePaint */
+ imapaint_redraw(1, texpaint, s.image);
-/* 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(ImBuf *ibuf, Object *ob, Mesh *mesh, TFace *tf, short *xy, float *imageco)
-{
- texpaint_pick_uv(ob, mesh, tf, xy, imageco);
- imageco[0] *= ibuf->x;
- imageco[1] *= ibuf->y;
-}
+ if (texpaint) {
+ if (s.warnpackedfile)
+ error("Painting in packed images is not supported: %s", s.warnpackedfile);
-void texturepaint_paint(short mousebutton)
-{
- Object *ob;
- Mesh *me;
- TFace *face, *face_old = 0;
- short xy[2], xy_old[2];
- //int a, index;
- Image *img=NULL, *img_old = NULL;
- ImBuf *brush, *canvas = 0;
- unsigned int face_index;
- char *warn_packed_file = 0;
- float uv[2], uv_old[2];
- extern VPaint Gvp;
- Brush tmpbrush;
-
- ob = OBACT;
- if (!ob || !(ob->lay & G.vd->lay)) return;
- me = get_mesh(ob);
- if (!me) 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);
-
- getmouseco_areawin(xy_old);
- while (get_mbut() & mousebutton) {
- getmouseco_areawin(xy);
- /* Check if cursor has moved */
- if ((xy[0] != xy_old[0]) || (xy[1] != xy_old[1])) {
-
- /* Get face to draw on */
- if (!facesel_face_pick(me, xy, &face_index, 0)) face = NULL;
- else face = (((TFace*)me->tface)+face_index);
-
- /* Check if this is another face. */
- if (face != face_old) {
- /* The active face changed, check the texture */
- if (face) {
- img = face->tpage;
- canvas = (img)? img->ibuf: NULL;
- }
- else {
- img = 0;
- }
-
- if (img != img_old) {
- /* Faces have different textures. Finish drawing in the old face. */
- if (face_old && canvas) {
- texpaint_compute_imageco(canvas, ob, me, face_old, xy, uv);
- imapaint_blend_line(canvas, brush, uv_old, uv);
- img_old->ibuf->userflags |= IB_BITMAPDIRTY;
- canvas = 0;
- }
-
- /* Create new canvas and start drawing in the new face. */
- if (img) {
- if (canvas && img->packedfile == 0) {
- /* MAART: skipx is not set most of the times. Make a guess. */
- 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);
- canvas->userflags |= IB_BITMAPDIRTY;
- }
- }
- else {
- if (img->packedfile) {
- warn_packed_file = img->id.name + 2;
- img = 0;
- }
- }
- }
- }
- else {
- /* Face changed and faces have the same texture. */
- if (canvas) {
- /* Finish drawing in the old face. */
- if (face_old) {
- texpaint_compute_imageco(canvas, ob, me, face_old, xy, uv);
- imapaint_blend_line(canvas, brush, uv_old, uv);
- img_old->ibuf->userflags |= IB_BITMAPDIRTY;
- }
-
- /* Start drawing in the new face. */
- if (face) {
- 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);
- canvas->userflags |= IB_BITMAPDIRTY;
- }
- }
- }
- }
- else {
- /* Same face, continue drawing */
- if (face && canvas) {
- /* Get the new (u,v) coordinates */
- texpaint_compute_imageco(canvas, ob, me, face, xy, uv);
- imapaint_blend_line(canvas, brush, uv_old, uv);
- canvas->userflags |= IB_BITMAPDIRTY;
- }
- }
-
- if (face && img) {
- /* Make OpenGL aware of a change in the texture */
- free_realtime_image(img);
- /* Redraw the view */
- scrarea_do_windraw(curarea);
- screen_swapbuffers();
- }
-
- xy_old[0] = xy[0];
- xy_old[1] = xy[1];
- uv_old[0] = uv[0];
- uv_old[1] = uv[1];
- face_old = face;
- img_old = img;
- }
+ persp(PERSP_WIN);
}
- IMB_freeImBuf(brush);
-
- if (warn_packed_file)
- error("Painting in packed images is not supported: %s", warn_packed_file);
-
- persp(PERSP_WIN);
-
- BIF_undo_push("UV face draw");
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWIMAGE, 0);
- allqueue(REDRAWHEADERS, 0);
+ /* todo: BIF_undo_push("Image paint"); */
}
void imagepaint_pick(short mousebutton)
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
index 6f05605cb30..87390954932 100644
--- a/source/blender/src/space.c
+++ b/source/blender/src/space.c
@@ -769,8 +769,10 @@ void BIF_undo(void)
wpaint_undo();
else if(G.f & G_VERTEXPAINT)
vpaint_undo();
- else if(G.f & G_TEXTUREPAINT); /* no texture paint undo yet */
- else if(curarea->spacetype==SPACE_IMAGE && (G.sima->flag & SI_DRAWTOOL));
+ else if(G.f & G_TEXTUREPAINT)
+ imagepaint_undo();
+ else if(curarea->spacetype==SPACE_IMAGE && (G.sima->flag & SI_DRAWTOOL))
+ imagepaint_undo();
else {
/* now also in faceselect mode */
if(U.uiflag & USER_GLOBALUNDO) {
@@ -792,6 +794,10 @@ void BIF_redo(void)
wpaint_undo();
else if(G.f & G_VERTEXPAINT)
vpaint_undo();
+ else if(G.f & G_TEXTUREPAINT)
+ imagepaint_undo();
+ else if(curarea->spacetype==SPACE_IMAGE && (G.sima->flag & SI_DRAWTOOL))
+ imagepaint_undo();
else {
/* includes faceselect now */
if(U.uiflag & USER_GLOBALUNDO) {
@@ -1011,7 +1017,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
vertex_paint();
}
else if (G.f & G_TEXTUREPAINT) {
- texturepaint_paint(origevent==LEFTMOUSE? L_MOUSE: R_MOUSE);
+ imagepaint_paint(origevent==LEFTMOUSE? L_MOUSE: R_MOUSE, 1);
}
break;
case MIDDLEMOUSE:
@@ -1847,6 +1853,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
wpaint_undo();
else if(G.f & G_VERTEXPAINT)
vpaint_undo();
+ else if(G.f & G_TEXTUREPAINT)
+ imagepaint_undo();
else if (G.f & G_FACESELECT)
uv_autocalc_tface();
else {
@@ -4075,7 +4083,7 @@ static void winqreadimagespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
scrarea_queue_winredraw(sa);
break;
case LEFTMOUSE:
- imagepaint_paint(origevent==LEFTMOUSE? L_MOUSE: R_MOUSE);
+ imagepaint_paint(origevent==LEFTMOUSE? L_MOUSE: R_MOUSE, 0);
break;
case RIGHTMOUSE:
imagepaint_pick(origevent==LEFTMOUSE? L_MOUSE: R_MOUSE);
diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c
index 10dd2a29024..0478968302c 100644
--- a/source/blender/src/usiblender.c
+++ b/source/blender/src/usiblender.c
@@ -126,6 +126,7 @@
#include "BDR_drawobject.h"
#include "BDR_editobject.h"
#include "BDR_editcurve.h"
+#include "BDR_imagepaint.h"
#include "BDR_vpaint.h"
#include "BPY_extern.h"
@@ -875,6 +876,7 @@ void exit_usiblender(void)
free_matcopybuf();
free_ipocopybuf();
free_vertexpaint();
+ free_imagepaint();
/* editnurb can remain to exist outside editmode */
freeNurblist(&editNurb);