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:
-rw-r--r--source/blender/blenkernel/BKE_brush.h27
-rw-r--r--source/blender/blenkernel/bad_level_call_stubs/stubs.c2
-rw-r--r--source/blender/blenkernel/intern/brush.c478
-rw-r--r--source/blender/blenkernel/intern/texture.c27
-rw-r--r--source/blender/blenloader/intern/readfile.c25
-rw-r--r--source/blender/blenloader/intern/writefile.c10
-rw-r--r--source/blender/imbuf/IMB_imbuf.h25
-rw-r--r--source/blender/imbuf/intern/rectop.c481
-rw-r--r--source/blender/include/blendef.h2
-rw-r--r--source/blender/include/butspace.h1
-rw-r--r--source/blender/makesdna/DNA_brush_types.h10
-rw-r--r--source/blender/render/extern/include/RE_render_ext.h4
-rw-r--r--source/blender/render/intern/source/texture.c4
-rw-r--r--source/blender/src/buttons_editing.c17
-rw-r--r--source/blender/src/buttons_shading.c30
-rw-r--r--source/blender/src/drawimage.c37
-rw-r--r--source/blender/src/header_buttonswin.c8
-rw-r--r--source/blender/src/headerbuttons.c53
-rw-r--r--source/blender/src/imagepaint.c779
19 files changed, 1256 insertions, 764 deletions
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 <math.h>
+
#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; a<MAX_MTEX; a++) {
+ mtex= brush->mtex[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; a<MAX_MTEX; a++) {
+ mtex= brush->mtex[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; a<MAX_MTEX; a++) {
+ if(br->mtex[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; a<MAX_MTEX; a++) {
+ if(br->mtex[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; a<MAX_MTEX; a++) {
+ mtex= brush->mtex[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; a<MAX_MTEX; a++)
+ brush->mtex[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; a<MAX_MTEX; a++)
+ if(brush->mtex[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; a<MAX_MTEX; a++)
+ if(brush->mtex[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; a<MAX_MTEX; a++) {
if(ma) mt= ma->mtex[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 <string.h>
#include <stdio.h>
#include <math.h>
-#include "PIL_time.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -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);