Brush Datablock:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 26 Jul 2006 22:29:23 +0000 (22:29 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 26 Jul 2006 22:29:23 +0000 (22:29 +0000)
- Added a new Brush datablock, only used by image paint, but intended
  to be used in texture paint, vertex paint, weight paint and sculpt
  mode also.
- Being a datablock, these brushes can be saved, appended and linked.
  They have a fake user by default, to make sure they are saved even if
  not selected.

Image Painting:

- Replaced the img module with C code in imagepaint.c
- Airbrush is no longer a separate tool, but rather an option that can
  be used for soften, smear and clone also.
- Blend modes mix, add, subtract, multiply, darken and lighten have been
  added, code taken directly from vertex paint.

Note to project files maintainers:

- The img module was removed from SCons and Makefiles, and this should
  be done in other build systems also. I'll wait to remove the module
  from cvs, to not break compilation.

26 files changed:
source/Makefile
source/blender/Makefile
source/blender/blenkernel/BKE_brush.h [new file with mode: 0644]
source/blender/blenkernel/BKE_main.h
source/blender/blenkernel/intern/brush.c [new file with mode: 0644]
source/blender/blenkernel/intern/library.c
source/blender/blenloader/intern/readblenentry.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/include/BDR_editface.h
source/blender/include/BDR_imagepaint.h
source/blender/include/blendef.h
source/blender/makesdna/DNA_ID.h
source/blender/makesdna/DNA_brush_types.h [new file with mode: 0644]
source/blender/makesdna/DNA_scene_types.h
source/blender/makesdna/intern/makesdna.c
source/blender/src/Makefile
source/blender/src/SConscript
source/blender/src/drawimage.c
source/blender/src/editface.c
source/blender/src/filesel.c
source/blender/src/header_image.c
source/blender/src/headerbuttons.c
source/blender/src/imagepaint.c
source/blender/src/space.c
source/nan_definitions.mk

index f02739544403aedd975a420abb0fd773af8c9885..ec78763506aee09382f91832fd5e8fbd30b079f2 100644 (file)
@@ -83,7 +83,6 @@ PYPLAYERLIB ?= $(PYLIB)
     GRPLIB += $(NAN_SOUNDSYSTEM)/lib/$(DEBUG_DIR)libSoundSystem.a
     GRPLIB += $(NAN_GHOST)/lib/$(DEBUG_DIR)libghost.a
     GRPLIB += $(NAN_STRING)/lib/$(DEBUG_DIR)libstring.a
-    GRPLIB += $(OCGDIR)/blender/img/$(DEBUG_DIR)libimg.a
     GRPLIB += $(OCGDIR)/blender/render/$(DEBUG_DIR)librender.a
     GRPLIB += $(OCGDIR)/blender/radiosity/$(DEBUG_DIR)libradiosity.a
     GRPLIB += $(NAN_OPENNL)/lib/$(DEBUG_DIR)libopennl.a
index ebae59ef0de09c1b804dc3cf239d0dc8caf813c2..5888186fcfc8f0e6525bc8fdec74018f280228d4 100644 (file)
@@ -34,7 +34,7 @@
 include nan_definitions.mk
 
 DIRS = blenloader readblenfile
-DIRS += avi imbuf img render radiosity blenlib blenkernel blenpluginapi
+DIRS += avi imbuf render radiosity blenlib blenkernel blenpluginapi
 DIRS += makesdna src yafray
 DIRS += python
 
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
new file mode 100644 (file)
index 0000000..89c6a3a
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * General operations for brushes.
+ */
+
+#ifndef BKE_BRUSH_H
+#define BKE_BRUSH_H
+
+struct ID;
+struct Brush;
+
+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 */
+int brush_set_nr(struct Brush **current_brush, int nr);
+int brush_delete(struct Brush **current_brush);
+void brush_toggle_fake_user(struct Brush *brush);
+int brush_clone_image_delete(struct Brush *brush);
+int brush_clone_image_set_nr(struct Brush *brush, int nr);
+void brush_check_exists(struct Brush **brush);
+
+#endif
+
index 1512ea28d4af085380ea2ef4448ae0aef140fdce..d385e357365afceb43d34b341dd8ca582a780d39 100644 (file)
@@ -75,6 +75,7 @@ typedef struct Main {
        ListBase armature;
        ListBase action;
        ListBase nodetree;
+       ListBase brush;
 } Main;
 
 
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
new file mode 100644 (file)
index 0000000..ca9d115
--- /dev/null
@@ -0,0 +1,317 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_image_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+
+#include "BKE_brush.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+
+Brush *add_brush(char *name)
+{
+       Brush *brush;
+
+       brush= alloc_libblock(&G.main->brush, ID_BR, name);
+
+       brush->rgb[0]= 1.0f;
+       brush->rgb[1]= 1.0f;
+       brush->rgb[2]= 1.0f;
+       brush->alpha= 0.2f;
+       brush->size= 25;
+       brush->timing= 100.0f;
+       brush->innerradius= 0.5f;
+       brush->clone.alpha= 0.5;
+
+       /* enable fake user by default */
+       brush_toggle_fake_user(brush);
+       
+       return brush;   
+}
+
+Brush *copy_brush(Brush *brush)
+{
+       Brush *brushn;
+       
+       brushn= copy_libblock(brush);
+
+       /* enable fake user by default */
+       if (!(brushn->id.flag & LIB_FAKEUSER))
+               brush_toggle_fake_user(brushn);
+       
+       return brushn;
+}
+
+/* not brush itself */
+void free_brush(Brush *brush)
+{
+}
+
+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
+           */
+       
+       Brush *brushn;
+       Scene *scene;
+       int local= 0, lib= 0;
+
+       if(brush->id.lib==0) return;
+
+       if(brush->clone.image) {
+       /* 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) {
+                       if(scene->id.lib) lib= 1;
+                       else local= 1;
+               }
+       
+       if(local && lib==0) {
+               brush->id.lib= 0;
+               brush->id.flag= LIB_LOCAL;
+               new_id(0, (ID *)brush, 0);
+
+               /* enable fake user by default */
+               if (!(brush->id.flag & LIB_FAKEUSER))
+                       brush_toggle_fake_user(brush);
+       }
+       else if(local && lib) {
+               brushn= copy_brush(brush);
+               brushn->id.us= 1; /* only keep fake user */
+               brushn->id.flag |= LIB_FAKEUSER;
+               
+               for(scene= G.main->scene.first; scene; scene=scene->id.next)
+                       if(scene->toolsettings->imapaint.brush==brush)
+                               if(scene->id.lib==0) {
+                                       scene->toolsettings->imapaint.brush= brushn;
+                                       brushn->id.us++;
+                                       brush->id.us--;
+                               }
+       }
+}
+
+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;
+               }
+       }
+}
+
+int brush_set_nr(Brush **current_brush, int nr)
+{
+       ID *idtest, *id;
+       
+       id= (ID*)(*current_brush);
+       idtest= (ID*)BLI_findlink(&G.main->brush, nr-1);
+       
+       if(idtest==0) { /* new brush */
+               if(id) idtest= (ID *)copy_brush((Brush *)id);
+               else idtest= (ID *)add_brush("Brush");
+               idtest->us--;
+       }
+       if(idtest!=id) {
+               brush_delete(current_brush);
+               *current_brush= (Brush *)idtest;
+               id_us_plus(idtest);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+int brush_delete(Brush **current_brush)
+{
+       if (*current_brush) {
+               (*current_brush)->id.us--;
+               *current_brush= NULL;
+               return 1;
+       }
+
+       return 0;
+}
+
+void brush_toggle_fake_user(Brush *brush)
+{
+       ID *id= (ID*)brush;
+       if(id) {
+               if(id->flag & LIB_FAKEUSER) {
+                       id->flag -= LIB_FAKEUSER;
+                       id->us--;
+               } else {
+                       id->flag |= LIB_FAKEUSER;
+                       id_us_plus(id);
+               }
+       }
+}
+
+int brush_clone_image_set_nr(Brush *brush, int nr)
+{
+       if(brush && nr > 0) {
+               Image *ima= (Image*)BLI_findlink(&G.main->image, nr-1);
+
+               if(ima) {
+                       brush_clone_image_delete(brush);
+                       brush->clone.image= ima;
+                       id_us_plus(&ima->id);
+                       brush->clone.offset[0]= brush->clone.offset[1]= 0.0f;
+
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+int brush_clone_image_delete(Brush *brush)
+{
+       if (brush && brush->clone.image) {
+               brush->clone.image->id.us--;
+               brush->clone.image= NULL;
+               return 1;
+       }
+
+       return 0;
+}
+
+void brush_check_exists(Brush **brush)
+{
+       if(*brush==NULL)
+               brush_set_nr(brush, 1);
+}
+
index 6992f2b29182f5089aee24e61ed5e4ed665c5be1..5628e4bc491f3265f839d54d72823fe3c02588ea 100644 (file)
@@ -77,6 +77,7 @@
 #include "DNA_node_types.h"
 #include "DNA_nla_types.h"
 #include "DNA_effect_types.h"
+#include "DNA_brush_types.h"
 
 #include "BLI_blenlib.h"
 #include "BLI_dynstr.h"
 #include "BKE_action.h"
 #include "BKE_node.h"
 #include "BKE_effect.h"
+#include "BKE_brush.h"
 
 #include "BPI_script.h"
 
@@ -193,6 +195,8 @@ ListBase *wich_libbase(Main *mainlib, short type)
                        return &(mainlib->action);
                case ID_NT:
                        return &(mainlib->nodetree);
+               case ID_BR:
+                       return &(mainlib->brush);
        }
        return 0;
 }
@@ -233,12 +237,13 @@ int set_listbasepointers(Main *main, ListBase **lb)
        lb[21]= &(main->sound);
        lb[22]= &(main->group);
        lb[23]= &(main->nodetree);
+       lb[24]= &(main->brush);
 
-       lb[24]= samples;
-       lb[25]= &(main->script);
-       lb[26]= NULL;
+       lb[25]= samples;
+       lb[26]= &(main->script);
+       lb[27]= NULL;
 
-       return 26;
+       return 27;
 }
 
 /* *********** ALLOC AND FREE *****************
@@ -332,7 +337,10 @@ static ID *alloc_libblock_notest(short type)
                        id = MEM_callocN(sizeof(bAction), "action");
                        break;
                case ID_NT:
-                       id = MEM_callocN(sizeof(bNodeTree), "action");
+                       id = MEM_callocN(sizeof(bNodeTree), "nodetree");
+                       break;
+               case ID_BR:
+                       id = MEM_callocN(sizeof(Brush), "brush");
                        break;
        }
        return id;
@@ -477,6 +485,9 @@ void free_libblock(ListBase *lb, void *idv)
                case ID_NT:
                        ntreeFreeTree((bNodeTree *)id);
                        break;
+               case ID_BR:
+                       free_brush((Brush *)id);
+                       break;
        }
 
        BLI_remlink(lb, id);
index 2da43013318dff90e6a7c8523f413338475f3b22..a16bd5a397205ff69a17f374d0e16d8a03df8fa4 100644 (file)
@@ -81,6 +81,7 @@ typedef struct {
 static IDType idtypes[]= {
        { ID_AC,                "Action",       IDTYPE_FLAGS_ISLINKABLE}, 
        { ID_AR,                "Armature", IDTYPE_FLAGS_ISLINKABLE}, 
+       { ID_BR,                "Brush",        IDTYPE_FLAGS_ISLINKABLE}, 
        { ID_CA,                "Camera",       IDTYPE_FLAGS_ISLINKABLE}, 
        { ID_CU,                "Curve",        IDTYPE_FLAGS_ISLINKABLE}, 
        { ID_GR,                "Group",        IDTYPE_FLAGS_ISLINKABLE}, 
index 51dfc9272516f965fbf1f188c3884edb17373594..17bf34f6f455f31d911b55b209d8ce6a0e522287 100644 (file)
@@ -58,6 +58,7 @@
 #include "DNA_armature_types.h"
 #include "DNA_ID.h"
 #include "DNA_actuator_types.h"
+#include "DNA_brush_types.h"
 #include "DNA_camera_types.h"
 #include "DNA_color_types.h"
 #include "DNA_controller_types.h"
@@ -1182,6 +1183,28 @@ static void test_pointer_array(FileData *fd, void **mat)
        }
 }
 
+/* ************ READ BRUSH *************** */
+
+/* library brush linking after fileread */
+static void lib_link_brush(FileData *fd, Main *main)
+{
+       Brush *brush;
+       
+       /* 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 */
+               }
+       }
+}
+
+/* brush itself has been read! */
+static void direct_link_brush(FileData *fd, Brush *brush)
+{
+       /* nothing to do yet - until brush gets textures */
+}
+
 /* ************ READ CurveMapping *************** */
 
 /* cuma itself has been read! */
@@ -2639,6 +2662,8 @@ static void lib_link_scene(FileData *fd, Main *main)
                        sce->world= newlibadr_us(fd, sce->id.lib, sce->world);
                        sce->set= newlibadr(fd, sce->id.lib, sce->set);
                        sce->ima= newlibadr_us(fd, sce->id.lib, sce->ima);
+                       sce->toolsettings->imapaint.brush=
+                               newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.brush);
 
                        base= sce->base.first;
                        while(base) {
@@ -3471,6 +3496,8 @@ static char *dataname(short id_code)
                case ID_TXT     : return "Data from TXT";
                case ID_SO: return "Data from SO";
                case ID_SAMPLE: return "Data from SAMPLE";
+               case ID_NT: return "Data from NT";
+               case ID_BR: return "Data from BR";
        }
        return "Data from Lib Block";
        
@@ -3604,6 +3631,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
                case ID_NT:
                        direct_link_nodetree(fd, (bNodeTree*)id);
                        break;
+               case ID_BR:
+                       direct_link_brush(fd, (Brush*)id);
+                       break;
        }
 
        oldnewmap_free_unused(fd->datamap);
@@ -5555,6 +5585,7 @@ static void lib_link_all(FileData *fd, Main *main)
        lib_link_vfont(fd, main);
        lib_link_screen_sequence_ipos(main);
        lib_link_nodetree(fd, main);    /* has to be done after scene/materials, this will verify group nodes */
+       lib_link_brush(fd, main);
 
        lib_link_mesh(fd, main);                /* as last: tpage images with users at zero */
 
@@ -5769,6 +5800,11 @@ static void expand_texture(FileData *fd, Main *mainvar, Tex *tex)
        expand_doit(fd, mainvar, tex->ipo);
 }
 
+static void expand_brush(FileData *fd, Main *mainvar, Brush *brush)
+{
+       /* nothing to do yet - until brush gets texture */
+}
+
 static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
 {
        bNode *node;
@@ -6232,6 +6268,9 @@ static void expand_main(FileData *fd, Main *mainvar)
                                        case ID_NT:
                                                expand_nodetree(fd, mainvar, (bNodeTree *)id);
                                                break;
+                                       case ID_BR:
+                                               expand_brush(fd, mainvar, (Brush *)id);
+                                               break;
                                        case ID_IP:
                                                expand_ipo(fd, mainvar, (Ipo *)id);
                                                break;
index ca7f75526dc6a50440d8857fe8dd6a3e0f06ee23..e3a67da94c3c7157736530411a877ce084c449f5 100644 (file)
@@ -105,6 +105,7 @@ Important to know is that 'streaming' has been added to files, for Blender Publi
 #include "DNA_armature_types.h"
 #include "DNA_action_types.h"
 #include "DNA_actuator_types.h"
+#include "DNA_brush_types.h"
 #include "DNA_controller_types.h"
 #include "DNA_curve_types.h"
 #include "DNA_constraint_types.h"
@@ -1592,6 +1593,15 @@ static void write_nodetrees(WriteData *wd, ListBase *idbase)
        }
 }
 
+static void write_brushes(WriteData *wd, ListBase *idbase)
+{
+       Brush *brush;
+       
+       for(brush=idbase->first; brush; brush= brush->id.next)
+               if (brush->id.us>0 || wd->current)
+                       writestruct(wd, ID_BR, "Brush", 1, brush);
+}
+
 static void write_global(WriteData *wd)
 {
        FileGlobal fg;
@@ -1650,6 +1660,7 @@ static int write_file_handle(int handle, MemFile *compare, MemFile *current, int
        write_textures (wd, &G.main->tex);
        write_meshs    (wd, &G.main->mesh);
        write_nodetrees(wd, &G.main->nodetree);
+       write_brushes  (wd, &G.main->brush);
        write_libraries(wd,  G.main->next);
 
        write_global(wd);
index abce31796db7ef213b0bceb189422cd20db16d53..d46f05667ba2310c7967347601708055664315cd 100644 (file)
@@ -54,7 +54,6 @@ void face_borderselect(void);
 void uv_autocalc_tface(void);
 void set_faceselect(void);
 void set_texturepaint(void);
-void face_draw(void);
 void get_same_uv(void);  
 void seam_mark_clear_tface(short mode);
 
index 5fd725ba934a3f2a3b3f64295dee0a6a4a13ac84..8824c63071dca5ed9453198fb7cb6ebac3fc307c 100644 (file)
 #ifndef BDR_IMAGEPAINT_H
 #define BDR_IMAGEPAINT_H
 
-/* ImagePaint.current */
-#define IMAGEPAINT_BRUSH 0
-#define IMAGEPAINT_AIRBRUSH 1
-#define IMAGEPAINT_SOFTEN 2
-#define IMAGEPAINT_AUX1 3
-#define IMAGEPAINT_AUX2 4
-#define IMAGEPAINT_SMEAR 5
-#define IMAGEPAINT_CLONE 6
-#define IMAGEPAINT_TOOL_SIZE 7
-
-/* ImagePaint.flag */
-#define IMAGEPAINT_DRAW_TOOL 1
-#define IMAGEPAINT_DRAW_TOOL_DRAWING 2
-#define IMAGEPAINT_DRAWING 4
-#define IMAGEPAINT_TORUS 8
-#define IMAGEPAINT_TIMED 16
-
-typedef struct ImagePaintTool {
-       float rgba[4];
-       int size;
-       float innerradius;
-       float timing;
-} ImagePaintTool;
-
-typedef struct ImagePaint {
-       struct Clone {
-               Image *image;
-               float offset[2];
-               float alpha;
-       } clone;
-
-       ImagePaintTool tool[IMAGEPAINT_TOOL_SIZE];
-
-       short flag, current;
-} ImagePaint;
-
-extern struct ImagePaint Gip;
-
 void imagepaint_redraw_tool(void);
 void imagepaint_paint(short mousebutton);
 void imagepaint_pick(short mousebutton);
 
+void texturepaint_paint();
+
 #endif /*  BDR_IMAGEPAINT_H */
 
index 3dd0dda31d35c4eb35bacddf6012e0e56e6a6e69..49873674917169a7f385e818f4fa3d7fd62c9aaf 100644 (file)
 #define B_SIMA_USE_ALPHA       371
 #define B_SIMA_SHOW_ALPHA      372
 #define B_SIMA_SHOW_ZBUF       373
+#define B_BRUSHBROWSE          374
+#define B_BRUSHDELETE          375
+#define B_BRUSHLOCAL           376
 
 /* BUTS: 400 */
 #define B_BUTSHOME             401
index 7e71da6df7675d45ff6fa42a0d9a0cb8e2f7f996..f9a824eec2731ecabbc472ed7b4b1eaca4c84e0f 100644 (file)
@@ -129,6 +129,7 @@ typedef struct Library {
 #define ID_SCRIPT      MAKE_ID2('P', 'Y')
 #define ID_FLUIDSIM    MAKE_ID2('F', 'S')
 #define ID_NT          MAKE_ID2('N', 'T')
+#define ID_BR          MAKE_ID2('B', 'R')
 
        /* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */
 #define ID_SEQ         MAKE_ID2('S', 'Q')
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
new file mode 100644 (file)
index 0000000..ff57849
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef DNA_BRUSH_TYPES_H
+#define DNA_BRUSH_TYPES_H
+
+#include "DNA_ID.h"
+
+typedef struct Brush {
+       ID id;
+       
+       short flag, blend;
+       int size;
+       float innerradius;
+       float timing;
+
+       float rgb[3];                                   /* color */
+       float alpha;                                    /* opacity */
+
+       struct Clone {
+               struct Image *image;            /* image for clone tool */
+               float offset[2];                        /* offset of clone image from canvas */
+               float alpha;                            /* transparency for drawing of clone image */
+       } clone;
+} Brush;
+
+/* Brush.flag */
+#define BRUSH_AIRBRUSH 1
+
+/* Brush.blend */
+#define BRUSH_BLEND_MIX        0
+#define BRUSH_BLEND_ADD        1
+#define BRUSH_BLEND_SUB        2
+#define BRUSH_BLEND_MUL        3
+#define BRUSH_BLEND_LIGHTEN 4
+#define BRUSH_BLEND_DARKEN     5
+
+#define PAINT_TOOL_DRAW                0
+#define PAINT_TOOL_SOFTEN      1
+#define PAINT_TOOL_SMEAR       2
+#define PAINT_TOOL_CLONE       3
+
+#endif
+
index 33edf65454e1a6f94161332e389a419b6e23c737..fe2b0cfa015f4c024eb32af9f727e7a450fb0508 100644 (file)
@@ -344,6 +344,12 @@ typedef struct ToolSettings {
        /* Select Group Threshold */
        float select_thresh;
 
+       /* Image Paint */
+       struct ImagePaintSettings {
+               struct Brush *brush;
+               short flag, tool;
+               int pad3;
+       } imapaint;
 } ToolSettings;
 
 typedef struct Scene {
@@ -537,6 +543,13 @@ typedef struct Scene {
 #define FFMPEG_MULTIPLEX_AUDIO  1
 #define FFMPEG_AUTOSPLIT_OUTPUT 2
 
+/* toolsettings->imagepaint_flag */
+#define IMAGEPAINT_TORUS                               1
+#define IMAGEPAINT_DRAWING                             2
+#define IMAGEPAINT_TIMED                               4
+#define IMAGEPAINT_DRAW_TOOL                   8
+#define IMAGEPAINT_DRAW_TOOL_DRAWING   16
+
 #ifdef __cplusplus
 }
 #endif
index 87174abab384cc271212f557d258da8de5ccf818..e7abcb1508e6e60472a858d4abe06d38516e8e6c 100644 (file)
@@ -125,6 +125,7 @@ char *includefiles[] = {
        "DNA_nla_types.h",
        "DNA_node_types.h",
        "DNA_color_types.h",
+       "DNA_brush_types.h",
        // if you add files here, please add them at the end
        // of makesdna.c (this file) as well
 
@@ -1133,4 +1134,5 @@ int main(int argc, char ** argv)
 #include "DNA_nla_types.h"
 #include "DNA_node_types.h"
 #include "DNA_color_types.h"
+#include "DNA_brush_types.h"
 /* end of list */
index dc7acc3d0d27e29136d918734c84f29f63793bca..3bfb17dc5866ada426dfd3b9f8d61ca7dabb3df6 100644 (file)
@@ -69,7 +69,6 @@ CPPFLAGS += -I../blenlib
 CPPFLAGS += -I../python
 CPPFLAGS += -I../makesdna
 CPPFLAGS += -I../imbuf
-CPPFLAGS += -I../img
 CPPFLAGS += -I../blenloader
 CPPFLAGS += -I..
 CPPFLAGS += -I../../kernel/gen_system
index 8c3de92545025341ee4029d94d1d4ed261c6749a..fdd920e27133bda5ab6741e6efc229f3718dc87f 100644 (file)
@@ -11,7 +11,7 @@ incs += ' ../include #/intern/bmfont ../imbuf ../render/extern/include'
 incs += ' #/intern/bsp/extern ../radiosity/extern/include'
 incs += ' #/intern/decimation/extern ../blenloader ../python'
 incs += ' ../../kernel/gen_system #/intern/SoundSystem ../readstreamglue'
-incs += ' ../img ../quicktime #/intern/elbeem/extern'
+incs += ' ../quicktime #/intern/elbeem/extern'
 incs += ' #/intern/ghost #/intern/opennl/extern'
 
 incs += ' ' + env['BF_PYTHON_INC']
index 5486c093bcf4d6e933cf78fff29335bdcddb3e25..94d7ddd0b231ede6f0356a919d8ba9cf83d274de 100644 (file)
@@ -50,6 +50,7 @@
 #include "IMB_imbuf.h"
 #include "IMB_imbuf_types.h"
 
+#include "DNA_brush_types.h"
 #include "DNA_camera_types.h"
 #include "DNA_color_types.h"
 #include "DNA_image_types.h"
@@ -62,6 +63,7 @@
 #include "DNA_space_types.h"
 #include "DNA_userdef_types.h"
 
+#include "BKE_brush.h"
 #include "BKE_colortools.h"
 #include "BKE_utildefines.h"
 #include "BKE_global.h"
 #include "BIF_renderwin.h"
 #include "BIF_space.h"
 #include "BIF_screen.h"
+#include "BIF_toolbox.h"
 #include "BIF_transform.h"
 
 #include "BSE_drawipo.h"
+#include "BSE_filesel.h"
 #include "BSE_headerbuttons.h"
 #include "BSE_trans_types.h"
 #include "BSE_view.h"
 
 static unsigned char *alloc_alpha_clone_image(int *width, int *height)
 {
+       Brush *brush = G.scene->toolsettings->imapaint.brush;
+       Image *image;
        unsigned int size, alpha;
        unsigned char *rect, *cp;
 
-       if(!Gip.clone.image)
+       if(!brush || !brush->clone.image)
                return NULL;
+       
+       image= brush->clone.image;
+       if(!image->ibuf)
+               load_image(image, IB_rect, G.sce, G.scene->r.cfra);
 
-       if(!Gip.clone.image->ibuf)
-               load_image(Gip.clone.image, IB_rect, G.sce, G.scene->r.cfra);
-
-       if(!Gip.clone.image->ibuf || !Gip.clone.image->ibuf->rect)
+       if(!image->ibuf || !image->ibuf->rect)
                return NULL;
 
-       rect= MEM_dupallocN(Gip.clone.image->ibuf->rect);
-
+       rect= MEM_dupallocN(image->ibuf->rect);
        if(!rect)
                return NULL;
 
-       *width= Gip.clone.image->ibuf->x;
-       *height= Gip.clone.image->ibuf->y;
+       *width= image->ibuf->x;
+       *height= image->ibuf->y;
 
        size= (*width)*(*height);
-       alpha= (unsigned char)255*Gip.clone.alpha;
+       alpha= (unsigned char)255*brush->clone.alpha;
        cp= rect;
 
        while(size-- > 0) {
@@ -144,18 +150,6 @@ static unsigned char *alloc_alpha_clone_image(int *width, int *height)
        return rect;
 }
 
-static void setcloneimage()
-{
-       if(G.sima->menunr > 0) {
-               Image *ima= (Image*)BLI_findlink(&G.main->image, G.sima->menunr-1);
-
-               if(ima) {
-                       Gip.clone.image= ima;
-                       Gip.clone.offset[0]= Gip.clone.offset[0]= 0.0;
-               }
-       }
-}
-
 static int image_preview_active(ScrArea *sa, float *xim, float *yim)
 {
        SpaceImage *sima= sa->spacedata.first;
@@ -692,27 +686,30 @@ static void draw_image_view_icon(void)
 
 static void draw_image_view_tool(void)
 {
-       ImagePaintTool *tool = &Gip.tool[Gip.current];
+       ToolSettings *settings= G.scene->toolsettings;
+       Brush *brush= settings->imapaint.brush;
        short mval[2];
        float radius;
        int draw= 0;
 
-       if(Gip.flag & IMAGEPAINT_DRAWING) {
-               if(Gip.flag & IMAGEPAINT_DRAW_TOOL_DRAWING)
+       if(brush) {
+               if(settings->imapaint.flag & IMAGEPAINT_DRAWING) {
+                       if(settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL_DRAWING)
+                               draw= 1;
+               }
+               else if(settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL)
                        draw= 1;
-       }
-       else if(Gip.flag & IMAGEPAINT_DRAW_TOOL)
-               draw= 1;
-       
-       if(draw) {
-               getmouseco_areawin(mval);
-
-               radius= tool->size*G.sima->zoom/2;
-               fdrawXORcirc(mval[0], mval[1], radius);
+               
+               if(draw) {
+                       getmouseco_areawin(mval);
 
-               if (tool->innerradius != 1.0) {
-                       radius *= tool->innerradius;
+                       radius= brush->size*G.sima->zoom/2;
                        fdrawXORcirc(mval[0], mval[1], radius);
+
+                       if (brush->innerradius != 1.0) {
+                               radius *= brush->innerradius;
+                               fdrawXORcirc(mval[0], mval[1], radius);
+                       }
                }
        }
 }
@@ -845,6 +842,8 @@ static void image_editvertex_buts(uiBlock *block)
 
 void do_imagebuts(unsigned short event)
 {
+       ToolSettings *settings= G.scene->toolsettings;
+
        switch(event) {
        case B_TRANS_IMAGE:
                image_editvertex_buts(NULL);
@@ -884,13 +883,15 @@ void do_imagebuts(unsigned short event)
                break;
 
        case B_SIMACLONEBROWSE:
-               setcloneimage();
-               allqueue(REDRAWIMAGE, 0);
+               if (settings->imapaint.brush)
+                       if (brush_clone_image_set_nr(settings->imapaint.brush, G.sima->menunr))
+                               allqueue(REDRAWIMAGE, 0);
                break;
                
        case B_SIMACLONEDELETE:
-               Gip.clone.image= NULL;
-               allqueue(REDRAWIMAGE, 0);
+               if (settings->imapaint.brush)
+                       if (brush_clone_image_delete(settings->imapaint.brush))
+                               allqueue(REDRAWIMAGE, 0);
                break;
 
        case B_SIMABRUSHCHANGE:
@@ -907,6 +908,37 @@ void do_imagebuts(unsigned short event)
                curvemapping_do_image(G.sima->cumap, G.sima->image);
                allqueue(REDRAWIMAGE, 0);
                break;
+       
+       case B_BRUSHBROWSE:
+               if(G.sima->menunr==-2) {
+                       activate_databrowse((ID*)settings->imapaint.brush, ID_BR, 0, B_BRUSHBROWSE, &G.sima->menunr, do_global_buttons);
+                       break;
+               }
+               else if(G.sima->menunr < 0) break;
+                       
+               if(brush_set_nr(&settings->imapaint.brush, G.sima->menunr)) {
+                       BIF_undo_push("Browse Brush");
+                       allqueue(REDRAWIMAGE, 0);
+               }
+               break;
+       case B_BRUSHDELETE:
+               if(brush_delete(&settings->imapaint.brush)) {
+                       BIF_undo_push("Unlink Brush");
+                       allqueue(REDRAWIMAGE, 0);
+               }
+               break;
+       case B_KEEPDATA:
+               brush_toggle_fake_user(settings->imapaint.brush);
+               allqueue(REDRAWIMAGE, 0);
+               break;
+       case B_BRUSHLOCAL:
+               if(settings->imapaint.brush && settings->imapaint.brush->id.lib) {
+                       if(okee("Make local")) {
+                               make_local_brush(settings->imapaint.brush);
+                               allqueue(REDRAWIMAGE, 0);
+                       }
+               }
+               break;
        }
 }
 
@@ -964,9 +996,11 @@ static void image_panel_paint(short cntrl) // IMAGE_HANDLER_PROPERTIES
        /* B_SIMABRUSHCHANGE only redraws and eats the mouse messages  */
        /* so that LEFTMOUSE does not 'punch' through the floating panel */
        /* B_SIMANOTHING */
-       ImagePaintTool *tool= &Gip.tool[Gip.current];
+       ToolSettings *settings= G.scene->toolsettings;
+       Brush *brush= settings->imapaint.brush;
        uiBlock *block;
        ID *id;
+       int yco, xco, butw;
 
        block= uiNewBlock(&curarea->uiblocks, "image_panel_paint", UI_EMBOSS, UI_HELV, curarea->win);
        uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
@@ -974,39 +1008,63 @@ static void image_panel_paint(short cntrl)       // IMAGE_HANDLER_PROPERTIES
        if(uiNewPanel(curarea, block, "Image Paint", "Image", 10, 230, 318, 204)==0)
                return;
 
-       uiBlockBeginAlign(block);
-       uiDefButF(block, COL, B_VPCOLSLI, "",           979,160,230,19, tool->rgba, 0, 0, 0, 0, "");
-       uiDefButF(block, NUMSLI, B_SIMANOTHING , "Opacity ",            979,140,230,19, tool->rgba+3, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
-       uiDefButI(block, NUMSLI, B_SIMANOTHING , "Size ",               979,120,230,19, &tool->size, 2, 64, 0, 0, "The size of the brush");
-       uiDefButF(block, NUMSLI, B_SIMANOTHING , "Fall ",               979,100,230,19, &tool->innerradius, 0.0, 1.0, 0, 0, "The fall off radius of the brush");
-
-       if(Gip.current == IMAGEPAINT_BRUSH || Gip.current == IMAGEPAINT_SMEAR)
-               uiDefButF(block, NUMSLI, B_SIMANOTHING , "Stepsize ",979,80,230,19, &tool->timing, 1.0, 100.0, 0, 0, "Repeating Paint On %of Brush diameter");
-       else
-               uiDefButF(block, NUMSLI, B_SIMANOTHING , "Flow ",       979,80,230,19, &tool->timing, 1.0, 100.0, 0, 0, "Paint Flow for Air Brush");
-       uiBlockEndAlign(block);
+       yco= 160;
 
        uiBlockBeginAlign(block);
-       uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Brush",               890,160,80,19, &Gip.current, 7.0, IMAGEPAINT_BRUSH, 0, 0, "Brush");
-       uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "AirBrush",            890,140,80,19, &Gip.current, 7.0, IMAGEPAINT_AIRBRUSH, 0, 0, "AirBrush");
-       uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Soften",              890,120,80,19, &Gip.current, 7.0, IMAGEPAINT_SOFTEN, 0, 0, "Soften");
-       uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Aux AB1",             890,100,80,19, &Gip.current, 7.0, IMAGEPAINT_AUX1, 0, 0, "Auxiliary Air Brush1");
-       uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Aux AB2",             890,80,80,19, &Gip.current, 7.0, IMAGEPAINT_AUX2, 0, 0, "Auxiliary Air Brush2");        
-       uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Smear",               890,60,80,19, &Gip.current, 7.0, IMAGEPAINT_SMEAR, 0, 0, "Smear");      
-       uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Clone",               890,40,80,19, &Gip.current, 7.0, IMAGEPAINT_CLONE, 0, 0, "Clone Brush / use RMB to drag source image"); 
+       uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Draw",                0  ,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_DRAW, 0, 0, "Draw brush");
+       uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Soften",              80 ,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SOFTEN, 0, 0, "Soften brush");
+       uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Smear",               160,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SMEAR, 0, 0, "Smear brush");   
+       uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Clone",               240,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_CLONE, 0, 0, "Clone brush, use RMB to drag source image");     
        uiBlockEndAlign(block);
+       yco -= 30;
 
-       uiBlockBeginAlign(block);       
-       id= (ID*)Gip.clone.image;
-       std_libbuttons(block, 979, 40, 0, NULL, B_SIMACLONEBROWSE, ID_IM, 0, id, 0, &G.sima->menunr, 0, 0, B_SIMACLONEDELETE, 0, 0);
-       uiDefButF(block, NUMSLI, B_SIMABRUSHCHANGE, "B ",979,20,230,19, &Gip.clone.alpha , 0.0, 1.0, 0, 0, "Blend clone image");
-       uiBlockEndAlign(block);
+       uiBlockSetCol(block, TH_BUT_SETTING2);
+       id= (ID*)settings->imapaint.brush;
+       xco= std_libbuttons(block, 0, yco, 0, NULL, B_BRUSHBROWSE, ID_BR, 0, id, NULL, &(G.sima->menunr), 0, B_BRUSHLOCAL, B_BRUSHDELETE, 0, B_KEEPDATA);
+       uiBlockSetCol(block, TH_AUTO);
+
+       if(brush && !brush->id.lib) {
+               butw= 320-(xco+10);
+
+               uiBlockBeginAlign(block);
+               uiDefButBitS(block, TOG|BIT, BRUSH_AIRBRUSH, B_SIMABRUSHCHANGE, "Airbrush",     xco+10,yco,butw,19, &brush->flag, 0, 0, 0, 0, "Keep applying paint effect while holding mouse (spray)");
+               uiDefButBitS(block, TOG|BIT, IMAGEPAINT_TORUS, B_SIMABRUSHCHANGE, "Wrap",       xco+10,yco-20,butw,19, &settings->imapaint.flag, 0, 0, 0, 0, "Enables torus wrapping");
+               uiBlockEndAlign(block);
+
+               uiDefButS(block, MENU, B_SIMANOTHING, "Mix %x0|Add %x1|Subtract %x2|Multiply %x3|Lighten %x4|Darken %x5", xco+10,yco-45,butw,19, &brush->blend, 0, 0, 0, 0, "Blending method for applying brushes");
+
+               yco -= 25;
+
+               uiBlockBeginAlign(block);
+               uiDefButF(block, COL, B_VPCOLSLI, "",                                   0,yco,200,19, brush->rgb, 0, 0, 0, 0, "");
+               uiDefButF(block, NUMSLI, B_SIMANOTHING, "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_SIMANOTHING, "Size ",                0,yco-40,200,19, &brush->size, 1, 200, 0, 0, "The size of the brush");
+               uiDefButF(block, NUMSLI, B_SIMANOTHING, "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_SIMANOTHING, "Flow ",        0,yco-80,200,19, &brush->timing, 1.0, 100.0, 0, 0, "Paint Flow for Air Brush");
+               else
+                       uiDefButF(block, NUMSLI, B_SIMANOTHING, "Stepsize ",0,yco-80,200,19, &brush->timing, 1.0, 100.0, 0, 0, "Repeating Paint On %% of Brush diameter");
+               uiBlockEndAlign(block);
+
+               yco -= 110;
+
+               if(settings->imapaint.tool == PAINT_TOOL_CLONE) {
+                       id= (ID*)brush->clone.image;
+                       uiBlockSetCol(block, TH_BUT_SETTING2);
+                       xco= std_libbuttons(block, 0, yco, 0, NULL, B_SIMACLONEBROWSE, ID_IM, 0, id, 0, &G.sima->menunr, 0, 0, B_SIMACLONEDELETE, 0, 0);
+                       uiBlockSetCol(block, TH_AUTO);
+                       if(id) {
+                               butw= 320-(xco+5);
+                               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");
+                       }
+               }
+       }
 
 #if 0
-       uiDefButBitS(block, TOG|BIT, IMAGEPAINT_DRAW_TOOL_DRAWING, B_SIMABRUSHCHANGE, "TD", 890,1,50,19, &Gip.flag, 0, 0, 0, 0, "Enables tool shape while drawing");
-       uiDefButBitS(block, TOG|BIT, IMAGEPAINT_DRAW_TOOL, B_SIMABRUSHCHANGE, "TP", 940,1,50,19, &Gip.flag, 0, 0, 0, 0, "Enables tool shape while not drawing");
+               uiDefButBitS(block, TOG|BIT, IMAGEPAINT_DRAW_TOOL_DRAWING, B_SIMABRUSHCHANGE, "TD", 0,1,50,19, &settings->imapaint.flag.flag, 0, 0, 0, 0, "Enables brush shape while drawing");
+               uiDefButBitS(block, TOG|BIT, IMAGEPAINT_DRAW_TOOL, B_SIMABRUSHCHANGE, "TP", 50,1,50,19, &settings->imapaint.flag.flag, 0, 0, 0, 0, "Enables brush shape while not drawing");
 #endif
-       uiDefButBitS(block, TOG|BIT, IMAGEPAINT_TORUS, B_SIMABRUSHCHANGE, "Wrap", 890,1,50,19, &Gip.flag, 0, 0, 0, 0, "Enables torus wrapping");
 }
 
 static void image_panel_curves_reset(void *cumap_v, void *unused)
@@ -1444,6 +1502,7 @@ void drawimagespace(ScrArea *sa, void *spacedata)
 {
        SpaceImage *sima= spacedata;
        ImBuf *ibuf= NULL;
+       Brush *brush;
        float col[3];
        unsigned int *rect;
        float x1, y1;
@@ -1617,7 +1676,8 @@ void drawimagespace(ScrArea *sa, void *spacedata)
                                }
                        }
                        
-                       if(Gip.current == IMAGEPAINT_CLONE) {
+                       brush= G.scene->toolsettings->imapaint.brush;
+                       if(brush && (G.scene->toolsettings->imapaint.tool == PAINT_TOOL_CLONE)) {
                                int w, h;
                                unsigned char *clonerect;
 
@@ -1627,8 +1687,8 @@ void drawimagespace(ScrArea *sa, void *spacedata)
 
                                if(clonerect) {
                                        int offx, offy;
-                                       offx = sima->zoom*ibuf->x * + Gip.clone.offset[0];
-                                       offy = sima->zoom*ibuf->y * + Gip.clone.offset[1];
+                                       offx = sima->zoom*ibuf->x * + brush->clone.offset[0];
+                                       offy = sima->zoom*ibuf->y * + brush->clone.offset[1];
 
                                        glEnable(GL_BLEND);
                                        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
index a906cc275fd99ae7cc33430a8b1d8bf7f5d6f4f3..9c6e244e5493368e99981314643b2d7b80337d72 100644 (file)
@@ -54,7 +54,6 @@
 #include "DNA_screen_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_view3d_types.h"
-#include "DNA_userdef_types.h"
 
 #include "BKE_utildefines.h"
 #include "BKE_depsgraph.h"
@@ -88,7 +87,6 @@
 #include "blendef.h"
 #include "butspace.h"
 
-#include "../img/IMG_Api.h"
 #include "BSE_trans_types.h"
 
 #include "BDR_unwrapper.h"
 
 
 /* returns 0 if not found, otherwise 1 */
-static int facesel_face_pick(Mesh *me, short *mval, unsigned int *index, short rect)
+int facesel_face_pick(Mesh *me, short *mval, unsigned int *index, short rect)
 {
        if (!me->tface || me->totface==0)
                return 0;
@@ -1506,7 +1504,7 @@ void set_texturepaint() /* toggle */
  * @param      org             origin of the view ray.
  * @param      dir             direction of the view ray.
  */
-static void get_pick_ray(short x, short y, float org[3], float dir[3])
+static void get_pick_ray(short *xy, float org[3], float dir[3])
 {
        double mvmatrix[16];
        double projmatrix[16];
@@ -1525,10 +1523,10 @@ static void get_pick_ray(short x, short y, float org[3], float dir[3])
        /* printf("viewport = (%4d, %4d, %4d, %4d)\n", viewport[0], viewport[1], viewport[2], viewport[3]); */
        /* printf("cursor = (%4d, %4d)\n", x, y); */
 
-       gluUnProject((GLdouble) x, (GLdouble) y, 0.0, mvmatrix, projmatrix, viewport, &px, &py, &pz);
+       gluUnProject((GLdouble) xy[0], (GLdouble) xy[1], 0.0, mvmatrix, projmatrix, viewport, &px, &py, &pz);
        org[0] = (float)px; org[1] = (float)py; org[2] = (float)pz;
        /* printf("world point at z=0.0 is (%f, %f, %f)\n", org[0], org[1], org[2]); */
-       gluUnProject((GLdouble) x, (GLdouble) y, 1.0, mvmatrix, projmatrix, viewport, &px, &py, &pz); 
+       gluUnProject((GLdouble) xy[0], (GLdouble) xy[1], 1.0, mvmatrix, projmatrix, viewport, &px, &py, &pz); 
        /* printf("world point at z=1.0 is (%f, %f, %f)\n", px, py, pz); */
        dir[0] = ((float)px) - org[0];
        dir[1] = ((float)py) - org[1];
@@ -1668,7 +1666,7 @@ static int face_get_vertex_coordinates(Mesh* mesh, TFace* face, float v1[3], flo
  * @param      u               (u,v) coordinate.
  * @param      v               (u,v) coordinate.
  */
-static void face_get_uv(TFace* face, int v1, int v2, int v3, float a, float b, float* u, float* v)
+static void face_get_uv(TFace* face, int v1, int v2, int v3, float a, float b, float *uv)
 {
        float uv01[2], uv21[2];
 
@@ -1692,8 +1690,8 @@ static void face_get_uv(TFace* face, int v1, int v2, int v3, float a, float b, f
        uv01[1] *= a;
        uv21[0] *= b;
        uv21[1] *= b;
-       *u = face->uv[v1][0] + (uv01[0] + uv21[0]);
-       *v = face->uv[v1][1] + (uv01[1] + uv21[1]);
+       uv[0] = face->uv[v1][0] + (uv01[0] + uv21[0]);
+       uv[1] = face->uv[v1][1] + (uv01[1] + uv21[1]);
 }
 
 /**
@@ -1711,7 +1709,7 @@ static void face_get_uv(TFace* face, int v1, int v2, int v3, float a, float b, f
  *                     0 == no intersection, (u,v) invalid
  *                     1 == intersection, (u,v) valid
  */
-static int face_pick_uv(Object* object, Mesh* mesh, TFace* face, short x, short y, float* u, float* v)
+int face_pick_uv(Object* object, Mesh* mesh, TFace* face, short *xy, float *uv)
 {
        float org[3], dir[3];
        float ab[2];
@@ -1720,7 +1718,7 @@ static int face_pick_uv(Object* object, Mesh* mesh, TFace* face, short x, short
        int num_verts;
 
        /* Get a view ray to intersect with the face */
-       get_pick_ray(xy, org, dir);
+       get_pick_ray(xy, org, dir);
 
        /* Convert local vertex coordinates to world */
        num_verts = face_get_vertex_coordinates(mesh, face, v1, v2, v3, v4);
@@ -1738,178 +1736,18 @@ static int face_pick_uv(Object* object, Mesh* mesh, TFace* face, short x, short
        result = triangle_ray_intersect(v2, v1, v3, org, dir, ab);
        if ( (num_verts == 3) || ((num_verts == 4) && (result > 1)) ) {
                /* Face is a triangle or a quad with a hit on the first triangle */
-               face_get_uv(face, 1, 0, 2, ab[0], ab[1], uv);
+               face_get_uv(face, 1, 0, 2, ab[0], ab[1], uv);
                /* printf("triangle 1, texture (u,v)=(%f, %f)\n", *u, *v); */
        }
        else {
                /* Face is a quad and no intersection with first triangle */
                result = triangle_ray_intersect(v4, v3, v1, org, dir, ab);
-               face_get_uv(face, 3, 2, 0, ab[0], ab[1], uv);
+               face_get_uv(face, 3, 2, 0, ab[0], ab[1], uv);
                /* printf("triangle 2, texture (u,v)=(%f, %f)\n", *u, *v); */
        }
        return result > 0;
 }
 
-/**
- * First attempt at drawing in the texture of a face.
- * @author     Maarten Gribnau
- */
-void face_draw()
-{
-       Object *ob;
-       Mesh *me;
-       TFace *face, *face_old = 0;
-       short xy[2], xy_old[2];
-       //int a, index;
-       Image *img=NULL, *img_old = NULL;
-       IMG_BrushPtr brush;
-       IMG_CanvasPtr canvas = 0;
-       unsigned int rowBytes, face_index;
-       char *warn_packed_file = 0;
-       float uv[2], uv_old[2];
-       extern VPaint Gvp;
-       short mousebut;
-
-       ob = OBACT;
-       if (!ob) {
-               error("No active object"); return;
-       }
-       if (!(ob->lay & G.vd->lay)) {
-               error("The active object is not in this layer"); return;
-       }
-       me = get_mesh(ob);
-       if (!me) {
-               error("The active object does not have a mesh obData"); return;
-       }
-
-       brush = IMG_BrushCreate(Gvp.size, Gvp.size, &Gvp.r);
-       if (!brush) {
-               error("Can't create brush"); return;
-       }
-
-       if (U.flag & USER_LMOUSESELECT) mousebut = R_MOUSE;
-       else mousebut = L_MOUSE;
-
-       persp(PERSP_VIEW);
-
-       getmouseco_areawin(xy_old);
-       while (get_mbut() & mousebut) {
-               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;
-                               }
-                               else {
-                                       img = 0;
-                               }
-
-                               if (img != img_old) {
-                                       /* Faces have different textures. Finish drawing in the old face. */
-                                       if (face_old && canvas) {
-                                               face_pick_uv(ob, me, face_old, xy[0], xy[1], &uv[0], &uv[1]);
-                                               IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]);
-                                               img_old->ibuf->userflags |= IB_BITMAPDIRTY;
-                                               /* Delete old canvas */
-                                               IMG_CanvasDispose(canvas);
-                                               canvas = 0;
-                                       }
-
-                                       /* Create new canvas and start drawing in the new face. */
-                                       if (img) {
-                                               if (img->ibuf && img->packedfile == 0) {
-                                                       /* MAART: skipx is not set most of the times. Make a guess. */
-                                                       rowBytes = img->ibuf->skipx ? img->ibuf->skipx : img->ibuf->x * 4;
-                                                       canvas = IMG_CanvasCreateFromPtr(img->ibuf->rect, img->ibuf->x, img->ibuf->y, rowBytes);
-                                                       if (canvas) {
-                                                               face_pick_uv(ob, me, face, xy_old[0], xy_old[1], &uv_old[0], &uv_old[1]);
-                                                               face_pick_uv(ob, me, face, xy[0], xy[1], &uv[0], &uv[1]);
-                                                               IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]);
-                                                               img->ibuf->userflags |= IB_BITMAPDIRTY;
-                                                       }
-                                               }
-                                               else {
-                                                       /* TODO: should issue warning that no texture is assigned */
-                                                       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) {
-                                                       face_pick_uv(ob, me, face_old, xy[0], xy[1], &uv[0], &uv[1]);
-                                                       IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]);
-                                                       img_old->ibuf->userflags |= IB_BITMAPDIRTY;
-                                               }
-
-                                               /* Start drawing in the new face. */
-                                               if (face) {
-                                                       face_pick_uv(ob, me, face, xy_old[0], xy_old[1], &uv_old[0], &uv_old[1]);
-                                                       face_pick_uv(ob, me, face, xy[0], xy[1], &uv[0], &uv[1]);
-                                                       IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]);
-                                                       img->ibuf->userflags |= IB_BITMAPDIRTY;
-                                               }
-                                       }
-                               }
-                       }
-                       else {
-                               /* Same face, continue drawing */
-                               if (face && canvas) {
-                                       /* Get the new (u,v) coordinates */
-                                       face_pick_uv(ob, me, face, xy[0], xy[1], &uv[0], &uv[1]);
-                                       IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]);
-                                       img->ibuf->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;
-               }
-       }
-
-       IMG_BrushDispose(brush);
-       if (canvas) {
-               IMG_CanvasDispose(canvas);
-               canvas = 0;
-       }
-
-       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);
-}
-
  /* Selects all faces which have the same uv-texture as the active face 
  * @author     Roel Spruit
  * @return     Void
index cb478bf9f59c06caefbb8835bea048c83b4ece15..bc1bfba9161f5cacc848d6956bdb05d59a0e9171 100644 (file)
@@ -2464,7 +2464,7 @@ void main_to_filelist(SpaceFile *sfile)
        if( sfile->dir[0]==0) {
                
                /* make directories */
-               sfile->totfile= 23;
+               sfile->totfile= 24;
                sfile->filelist= (struct direntry *)malloc(sfile->totfile * sizeof(struct direntry));
                
                for(a=0; a<sfile->totfile; a++) {
@@ -2495,6 +2495,7 @@ void main_to_filelist(SpaceFile *sfile)
                sfile->filelist[20].relname= BLI_strdup("Armature");
                sfile->filelist[21].relname= BLI_strdup("Action");
                sfile->filelist[22].relname= BLI_strdup("NodeTree");
+               sfile->filelist[23].relname= BLI_strdup("Brush");
                
                qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_name);
        }
index 4d87f3c9c56ed68fe1aaf0ca1ec9996d147abc75..a21518c17e15edf402b67fda90bb112b3bc91b67 100644 (file)
@@ -54,6 +54,7 @@
 
 #include "BDR_drawmesh.h"
 #include "BDR_unwrapper.h"
+#include "BKE_brush.h"
 #include "BKE_global.h"
 #include "BKE_image.h"
 #include "BKE_library.h"
@@ -315,7 +316,9 @@ void do_image_buttons(unsigned short event)
                break;
 
        case B_SIMAGEPAINTTOOL:
-               // check for packed file here
+               if(G.sima->flag & SI_DRAWTOOL)
+                       /* add new brush if none exists */
+                       brush_check_exists(&G.scene->toolsettings->imapaint.brush);
                allqueue(REDRAWIMAGE, 0);
                allqueue(REDRAWVIEW3D, 0);
                break;
index 3440b5b0c18c5e4b27d7a97638864d160db0afd3..3ec3a58f9b3e9491b3129817a1c5636bc9e083cf 100644 (file)
@@ -251,7 +251,7 @@ int std_libbuttons(uiBlock *block, short xco, short yco,
        if(browse) {
                char *extrastr= NULL;
                
-               if(ELEM(id_code, ID_MA, ID_TE)) add_addbutton= 1;
+               if(ELEM3(id_code, ID_MA, ID_TE, ID_BR)) add_addbutton= 1;
                        
                lb= wich_libbase(G.main, id_code);
                
@@ -261,7 +261,7 @@ int std_libbuttons(uiBlock *block, short xco, short yco,
                        uiBlockSetCol(block, TH_BUT_SETTING2);
                }
                
-               if ELEM7( id_code, ID_SCE, ID_SCR, ID_MA, ID_TE, ID_WO, ID_IP, ID_AC) extrastr= "ADD NEW %x 32767";
+               if ELEM8( id_code, ID_SCE, ID_SCR, ID_MA, ID_TE, ID_WO, ID_IP, ID_AC, ID_BR) extrastr= "ADD NEW %x 32767";
                else if (id_code==ID_TXT) extrastr= "OPEN NEW %x 32766 |ADD NEW %x 32767";
                else if (id_code==ID_SO) extrastr= "OPEN NEW %x 32766";
                
index 3aed860442f9cbb63a3808f4b9802f167a4e1c38..627d3aaf18fdfdaeeb1baea94afc26712d6aede2 100644 (file)
 #include <config.h>
 #endif
 
+#include "MEM_guardedalloc.h"
+
 #ifdef WIN32
 #include "BLI_winstuff.h"
 #endif
 
 #include "IMB_imbuf_types.h"
 
+#include "DNA_brush_types.h"
 #include "DNA_image_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
 
+#include "BKE_brush.h"
 #include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_utildefines.h"
 
 #include "BIF_mywindow.h"
 #include "BIF_screen.h"
 
 #include "BSE_drawipo.h"
 #include "BSE_trans_types.h"
+#include "BSE_view.h"
 
 #include "BDR_drawmesh.h"
 #include "BDR_imagepaint.h"
 #include "BDR_vpaint.h"
 
-#include "IMG_Api.h"
-
+#include "blendef.h"
 #include "mydevice.h"
 
+/* ImagePaintPixmap */
+
+#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); }
+
+typedef struct ImagePaintPixmap {
+       unsigned int width, height, rowbytes, shared;
+       char *rect;
+} ImagePaintPixmap;
+
+static ImagePaintPixmap *imapaint_pixmap_new(unsigned int w, unsigned int h, char *rect)
+{
+       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 */
+
+typedef struct ImagePaintBrush {
+       ImagePaintPixmap *pixmap;
+       float rgb[3], alpha;
+       unsigned int inner_radius, outer_radius;
+       short torus, blend;
+} 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);
+
+       for (y=0; y < pm->height; y++) {
+               dst = pm->rect + y*pm->rowbytes;
+
+               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 (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;
+
+                               IMAPAINT_RGB_COPY(dst, src);
+                               dst[3] = IMAPAINT_FLOAT_TO_CHAR(a);
+                       }
+                       else {
+                               IMAPAINT_RGBA_COPY(dst, src);
+                       }
+               }
+       }
+}
+
+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)
+{
+       int x = (int)(pos[0]*pm->width - bpm->width/2);
+       int y = (int)(pos[1]*pm->height - 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 (x < 0) {
+               dim[0] += x;
+               off[0] = 0;
+               boff[0] = -x;
+       }
+       else {
+               off[0] = x;
+               boff[0] = 0;
+       }
+
+       if (y < 0) {
+               dim[1] += y;
+               off[1] = 0;
+               boff[1] = -y;
+       }
+       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]*pm->width - bpm->width/2);
+       out_off[1] = (int)(pos[1]*pm->height - bpm->height/2);
+
+       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);
+               }
+       }
+}
+
+static int imapaint_pixmap_add_if(ImagePaintPixmap *pm, unsigned int x, unsigned int y, float *outrgb, short torus)
+{
+       char *inrgb;
+       float finrgb[3];
+
+       if ((x >= pm->width) || (y >= pm->height)) {
+               if (torus)
+                       inrgb = imapaint_pixmap_get_rgba_torus(pm, x, y);
+               else
+                       return 0;
+       }
+       else
+               inrgb = imapaint_pixmap_get_rgba(pm, x, y);
+
+       IMAPAINT_CHAR_RGB_TO_FLOAT(finrgb, inrgb);
+       IMAPAINT_FLOAT_RGB_ADD(outrgb, finrgb);
+
+       return 1;
+}
+
+/* ImagePaintPixmap Tools */
+
+static void imapaint_blend_line(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *start, float *end)
+{
+       float numsteps, t, pos[2];
+       int step, d[2];
+
+       d[0] = (int)((end[0] - start[0])*pm->width);
+       d[1] = (int)((end[1] - start[1])*pm->height);
+       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/pm->width;
+               pos[1] = start[1] + d[1]*t/pm->height;
+
+               if (brush->torus)
+                       imapaint_pixmap_blend_torus(pm, brush->pixmap, pos, brush->blend);
+               else
+                       imapaint_pixmap_blend(pm, brush->pixmap, pos, brush->blend);
+       }
+}
+
+static void imapaint_soften_sharpen(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *pos, short sharpen)
+{
+       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], finrgb[3];
+       short torus= brush->torus;
+       char *inrgb, *out;
+
+       if (torus) {
+               dim[0] = bpm->width;
+               dim[1] = bpm->width;
+               in_off[0] = (int)(pos[0]*pm->width - bpm->width/2);
+               in_off[1] = (int)(pos[1]*pm->height - 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;
+       }
+
+       for (y=0; y < dim[1]; y++) {
+               for (x=0; x < dim[0]; x++) {
+                       /* 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 (sharpen)
+                               IMAPAINT_FLOAT_RGB_COPY(finrgb, 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_pixmap_add_if(pm, xi  , yi-1, outrgb, torus);
+                       count += imapaint_pixmap_add_if(pm, 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);
+
+                       outrgb[0] /= count;
+                       outrgb[1] /= count;
+                       outrgb[2] /= count;
+
+                       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]);
+                       }
+
+                       /* 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);
+               }
+       }
+
+       if (torus)
+               imapaint_pixmap_blend_torus(pm, bpm, pos, brush->blend);
+       else
+               imapaint_pixmap_blend(pm, bpm, pos, brush->blend);
+}
+
+static void imapaint_lift_smear(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *pos)
+{
+       ImagePaintPixmap *bpm = brush->pixmap;
+       int in_off[2], x, y;
+       char *out, *in;
+
+       in_off[0] = (int)(pos[0]*pm->width - bpm->width/2);
+       in_off[1] = (int)(pos[1]*pm->height - 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);
+               }
+       }
+}
+
+static void imapaint_smear(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *start, float *end)
+{
+       float pos[2];
+
+       pos[0]= 2*start[0] - end[0];
+       pos[1]= 2*start[1] - end[1];
+
+       imapaint_lift_smear(pm, brush, pos);
+       imapaint_blend_line(pm, brush, start, end);
+}
+
+static void imapaint_lift_clone(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *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);
+
+       in_off[0] = (int)(pos[0]*pm->width - bpm->width/2);
+       in_off[1] = (int)(pos[1]*pm->height - 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) {
+                       xi = in_off[0] + x;
+                       yi = in_off[1] + y;
+
+                       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_clone(ImagePaintPixmap *pm, ImagePaintPixmap *cpm, ImagePaintBrush *brush, float *start, float *off)
+{
+       float pos[2];
+
+       pos[0]= start[0] - off[0];
+       pos[1]= start[1] - off[1];
+
+       imapaint_lift_clone(cpm, brush, pos);
+       imapaint_pixmap_blend(pm, brush->pixmap, start, brush->blend);
+}
+
+/* 2D image paint */
+
+#if 0
 struct ImagePaint Gip = {
        {NULL, {0.0f, 0.0f}, 0.5f},
         {{{1.0f, 1.0f, 1.0f, 0.2f}, 25, 0.5f, 100.0f}, /* brush */
@@ -82,73 +529,83 @@ struct ImagePaint Gip = {
         {{1.0f, 1.0f, 1.0f, 0.5f}, 25, 0.1f,  20.0f}}, /* clone */
         0, IMAGEPAINT_BRUSH
 };
+#endif
 
-static int imagepaint_init(IMG_BrushPtr **brush, IMG_CanvasPtr **canvas, IMG_CanvasPtr **clonecanvas)
+static ImagePaintBrush *imapaint_init_brush()
 {
-       ImBuf *ibuf= NULL, *cloneibuf= NULL;
-       ImagePaintTool *tool= &Gip.tool[Gip.current];
+       ToolSettings *settings= G.scene->toolsettings;
+       Brush *brush= settings->imapaint.brush;
 
-       /* verify that we can paint */
-       if(!G.sima->image || !G.sima->image->ibuf || !G.sima->image->ibuf->rect)
-               return 0;
-       else if(G.sima->image->packedfile) {
-               error("Painting in packed images not supported");
-               return 0;
-       }
+       if (!brush)
+               return NULL;
 
-       ibuf= G.sima->image->ibuf;
+       /* initialize paint settings */
+       if(brush->flag & BRUSH_AIRBRUSH)
+               settings->imapaint.flag |= IMAGEPAINT_TIMED;
+       else
+               settings->imapaint.flag &= ~IMAGEPAINT_TIMED;
 
-       if(Gip.current == IMAGEPAINT_CLONE) {
-               if(!Gip.clone.image || !Gip.clone.image->ibuf)
-                       return 0;
+       /* create brush */
+       return imapaint_brush_new(brush->size, brush->size, brush->rgb, brush->alpha, brush->innerradius);
+}
 
-               cloneibuf= Gip.clone.image->ibuf;
-       }
+static void imapaint_free_brush(ImagePaintBrush *brush)
+{
+       imapaint_brush_free(brush);
+}
 
-       /* create brush */
-       *brush= IMG_BrushCreate(tool->size, tool->size, tool->rgba);
-       IMG_BrushSetInnerRaduisRatio(*brush, tool->innerradius);
+static ImagePaintPixmap *imapaint_init_canvas(ImagePaintPixmap **clonecanvas)
+{
+       ImBuf *ibuf= NULL, *cloneibuf= NULL;
+       ImagePaintPixmap *canvas;
+       ToolSettings *settings= G.scene->toolsettings;
+       Brush *brush= settings->imapaint.brush;
 
-       /* create canvas */
-       *canvas= IMG_CanvasCreateFromPtr(ibuf->rect, ibuf->x, ibuf->y, ibuf->x*4);
+       /* verify that we can paint and create canvas */
+       if(!G.sima->image || !G.sima->image->ibuf || !G.sima->image->ibuf->rect)
+               return NULL;
+       else if(G.sima->image->packedfile)
+               return NULL;
 
-       if(Gip.current == IMAGEPAINT_CLONE) {
-               int w= cloneibuf->x, h= cloneibuf->y;
-               *clonecanvas= IMG_CanvasCreateFromPtr(cloneibuf->rect, w, h, cloneibuf->x*4);
+       ibuf= G.sima->image->ibuf;
+       canvas= imapaint_pixmap_new(ibuf->x, ibuf->y, (char*)ibuf->rect);
+
+       if (clonecanvas) {
+               /* create clone canvas */
+               if(brush && (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;
+                       *clonecanvas= imapaint_pixmap_new(w, h, (char*)cloneibuf->rect);
+               }
+               else
+                       *clonecanvas= NULL;
        }
-       else
-               *clonecanvas= NULL;
-       
-       /* initialize paint settings */
-       if((Gip.current == IMAGEPAINT_AIRBRUSH) ||
-          (Gip.current ==  IMAGEPAINT_AUX1) ||
-          (Gip.current ==  IMAGEPAINT_AUX2))
-               Gip.flag |= IMAGEPAINT_TIMED;
-       else
-               Gip.flag &= ~IMAGEPAINT_TIMED;
-       
-       return 1;
+
+       return canvas;
 }
 
-static void imagepaint_free(IMG_BrushPtr *brush, IMG_CanvasPtr *canvas, IMG_CanvasPtr *clonecanvas)
+static void imapaint_free_canvas(ImagePaintPixmap *canvas, ImagePaintPixmap *clonecanvas)
 {
-       IMG_BrushDispose(brush);
-       IMG_CanvasDispose(canvas);
-
-       if(Gip.current == IMAGEPAINT_CLONE)
-               IMG_CanvasDispose(clonecanvas);
+       imapaint_pixmap_free(canvas);
+       if(clonecanvas)
+               imapaint_pixmap_free(clonecanvas);
 }
 
-void imagepaint_redraw_tool(void)
+void imapaint_redraw_tool(void)
 {
-       if(Gip.flag & IMAGEPAINT_DRAW_TOOL_DRAWING)
+       if(G.scene->toolsettings->imapaint.flag & IMAGEPAINT_DRAW_TOOL_DRAWING)
                force_draw(0);
 }
 
-static void imagepaint_redraw(int final, int painted)
+static void imapaint_redraw(int final, int painted)
 {
        if(!final && !painted) {
-               imagepaint_redraw_tool();
+               imapaint_redraw_tool();
                return;
        }
 
@@ -166,66 +623,76 @@ static void imagepaint_redraw(int final, int painted)
                allqueue(REDRAWHEADERS, 0);
 }
 
-static void imagepaint_compute_uvco(short *mval, float *uv)
+static void imapaint_compute_uvco(short *mval, float *uv)
 {
        areamouseco_to_ipoco(G.v2d, mval, &uv[0], &uv[1]);
 }
 
-static void imagepaint_paint_tool(IMG_BrushPtr *brush, IMG_CanvasPtr *canvas, IMG_CanvasPtr *clonecanvas, float *prevuv, float *uv)
+static void imapaint_paint_tool(ImagePaintBrush *brush, ImagePaintPixmap *canvas, ImagePaintPixmap *clonecanvas, float *prevuv, float *uv)
 {
-       int torus = Gip.flag & IMAGEPAINT_TORUS;
-       ImagePaintTool *tool= &Gip.tool[Gip.current];
-
-       if(Gip.current == IMAGEPAINT_SOFTEN)
-               IMG_CanvasSoftenAt(canvas, prevuv[0], prevuv[1], tool->size, tool->rgba[3], tool->innerradius, torus);
-       else if(Gip.current == IMAGEPAINT_SMEAR)
-               IMG_CanvasSmear(canvas, prevuv[0], prevuv[1], uv[0], uv[1], tool->size, tool->rgba[3], tool->innerradius, torus);
-       else if(Gip.current == IMAGEPAINT_CLONE) {
-               float offx= Gip.clone.offset[0];
-               float offy= Gip.clone.offset[1];
-
-               IMG_CanvasCloneAt(canvas, clonecanvas, prevuv[0], prevuv[1], offx, offy, tool->size, tool->rgba[3], tool->innerradius);
-       }
-       else if(Gip.flag & IMAGEPAINT_TIMED) 
-               IMG_CanvasDrawLineUVEX(canvas, brush,  uv[0], uv[1],uv[0], uv[1], torus);
+       ToolSettings *settings= G.scene->toolsettings;
+       Brush *curbrush= settings->imapaint.brush;
+
+       brush->torus= (settings->imapaint.flag & IMAGEPAINT_TORUS)? 1: 0;
+       brush->blend= curbrush->blend;
+
+       if(settings->imapaint.tool == PAINT_TOOL_SOFTEN)
+               imapaint_soften_sharpen(canvas, brush, prevuv, 0);
+       else if(settings->imapaint.tool == PAINT_TOOL_SMEAR)
+               imapaint_smear(canvas, brush, prevuv, uv);
+       else if(settings->imapaint.tool == PAINT_TOOL_CLONE)
+               imapaint_clone(canvas, clonecanvas, brush, prevuv, curbrush->clone.offset);
+       else if(curbrush->flag & BRUSH_AIRBRUSH)
+               imapaint_blend_line(canvas, brush, uv, uv);
        else
-               IMG_CanvasDrawLineUVEX(canvas, brush, prevuv[0], prevuv[1], uv[0], uv[1], torus);
+               imapaint_blend_line(canvas, brush, prevuv, uv);
 }
 
 void imagepaint_paint(short mousebutton)
 {
-       IMG_BrushPtr *brush;
-       IMG_CanvasPtr *canvas, *clonecanvas;
+       ImagePaintBrush *brush;
+       ImagePaintPixmap *canvas, *clonecanvas=NULL;
        short prevmval[2], mval[2];
        double prevtime, curtime;
        float prevuv[2], uv[2];
        int paint= 0, moved= 0, firsttouch=1 ;
-       ImagePaintTool *tool= &Gip.tool[Gip.current];
+       ToolSettings *settings= G.scene->toolsettings;
+       Brush *curbrush= settings->imapaint.brush;
 
-       if(!imagepaint_init(&brush, &canvas, &clonecanvas))
+       if (!(canvas = imapaint_init_canvas(&clonecanvas))) {
+               if(G.sima->image && G.sima->image->packedfile)
+                       error("Painting in packed images not supported");
+               return;
+       }
+       else if (!(brush = imapaint_init_brush())) {
+               imapaint_free_canvas(canvas, clonecanvas);
                return;
+       }
        
        getmouseco_areawin(prevmval);
        prevtime = PIL_check_seconds_timer();
 
-       Gip.flag |= IMAGEPAINT_DRAWING;
+       settings->imapaint.flag |= IMAGEPAINT_DRAWING;
 
        while(get_mbut() & mousebutton) {
                getmouseco_areawin(mval);
 
-               moved= paint= (prevmval[0] != mval[0]) || (prevmval[1] != mval[1]);
+               if(firsttouch)
+                       moved= paint= 1;
+               else
+                       moved= paint= (prevmval[0] != mval[0]) || (prevmval[1] != mval[1]);
 
-               if(Gip.flag & IMAGEPAINT_TIMED) {
+               if(settings->imapaint.flag & IMAGEPAINT_TIMED) {
                        /* see if need to draw because of timer */
                        curtime = PIL_check_seconds_timer();
 
-                       if(((curtime - prevtime) > (5.0/tool->timing)) || firsttouch) {
+                       if(((curtime - prevtime) > (5.0/curbrush->timing)) || firsttouch) {
                                prevtime= curtime;
                                paint= 1;
                        }
                        else paint= 0;
                }
-               else if(paint) {
+               else if(paint && !firsttouch) {
                        /* check if we moved enough to draw */
                        float dmval[2], d, dlimit;
 
@@ -233,7 +700,7 @@ void imagepaint_paint(short mousebutton)
                        dmval[1]= prevmval[1] - mval[1];
 
                        d= sqrt(dmval[0]*dmval[0] + dmval[1]*dmval[1]);
-                       dlimit= tool->size*G.sima->zoom*tool->timing/200.0;
+                       dlimit= curbrush->size*G.sima->zoom*curbrush->timing/200.0;
 
                        if (d < dlimit)
                                paint= 0;
@@ -241,10 +708,10 @@ void imagepaint_paint(short mousebutton)
 
                if(paint) {
                        /* do the actual painting */
-                       imagepaint_compute_uvco(prevmval, prevuv);
-                       imagepaint_compute_uvco(mval, uv);
+                       imapaint_compute_uvco(prevmval, prevuv);
+                       imapaint_compute_uvco(mval, uv);
 
-                       imagepaint_paint_tool(brush, canvas, clonecanvas, prevuv, uv);
+                       imapaint_paint_tool(brush, canvas, clonecanvas, prevuv, uv);
 
                        prevmval[0]= mval[0];
                        prevmval[1]= mval[1];
@@ -252,25 +719,27 @@ void imagepaint_paint(short mousebutton)
                firsttouch = 0;
 
                if(paint)
-                       imagepaint_redraw(0, paint);
-               else if(moved && (Gip.flag & IMAGEPAINT_DRAW_TOOL))
-                       imagepaint_redraw(0, paint);
+                       imapaint_redraw(0, paint);
+               else if(moved && (settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL))
+                       imapaint_redraw(0, paint);
        }
 
-       Gip.flag &= ~IMAGEPAINT_DRAWING;
+       settings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
 
-       imagepaint_free(brush, canvas, clonecanvas);
+       imapaint_free_brush(brush);
+       imapaint_free_canvas(canvas, clonecanvas);
        G.sima->image->ibuf->userflags |= IB_BITMAPDIRTY;
 
-       imagepaint_redraw(1, 0);
+       imapaint_redraw(1, 0);
 }
 
 void imagepaint_pick(short mousebutton)
 {
-       ImagePaintTool *tool= &Gip.tool[Gip.current];
+       ToolSettings *settings= G.scene->toolsettings;
+       Brush *brush= settings->imapaint.brush;
 
-       if(Gip.current == IMAGEPAINT_CLONE) {
-               if(Gip.clone.image && Gip.clone.image->ibuf) {
+       if(brush && (settings->imapaint.tool == PAINT_TOOL_CLONE)) {
+               if(brush->clone.image && brush->clone.image->ibuf) {
                        short prevmval[2], mval[2];
                        float prevuv[2], uv[2];
                
@@ -281,11 +750,11 @@ void imagepaint_pick(short mousebutton)
 
                                if((prevmval[0] != mval[0]) || (prevmval[1] != mval[1]) ) {
                                        /* mouse moved, so move the clone image */
-                                       imagepaint_compute_uvco(prevmval, prevuv);
-                                       imagepaint_compute_uvco(mval, uv);
+                                       imapaint_compute_uvco(prevmval, prevuv);
+                                       imapaint_compute_uvco(mval, uv);
 
-                                       Gip.clone.offset[0] += uv[0] - prevuv[0];
-                                       Gip.clone.offset[1] += uv[1] - prevuv[1];
+                                       brush->clone.offset[0] += uv[0] - prevuv[0];
+                                       brush->clone.offset[1] += uv[1] - prevuv[1];
 
                                        force_draw(0);
 
@@ -295,13 +764,172 @@ void imagepaint_pick(short mousebutton)
                        }
                }
        }
-       else {
+       else if(brush) {
                extern VPaint Gvp;
 
                sample_vpaint();
-               tool->rgba[0]= Gvp.r;
-               tool->rgba[1]= Gvp.g;
-               tool->rgba[2]= Gvp.b;
+               brush->rgb[0]= Gvp.r;
+               brush->rgb[1]= Gvp.g;
+               brush->rgb[2]= Gvp.b;
+       }
+}
+
+/* these will be moved */
+int facesel_face_pick(Mesh *me, short *mval, unsigned int *index, short rect);
+int face_pick_uv(Object* object, Mesh* mesh, TFace* face, short *xy, float *uv);
+
+void texturepaint_paint()
+{
+       Object *ob;
+       Mesh *me;
+       TFace *face, *face_old = 0;
+       short xy[2], xy_old[2];
+       //int a, index;
+       Image *img=NULL, *img_old = NULL;
+       ImagePaintBrush *brush;
+       ImagePaintPixmap *canvas = 0;
+       unsigned int face_index, mousebutton;
+       char *warn_packed_file = 0;
+       float uv[2], uv_old[2];
+       extern VPaint Gvp;
+       ImBuf *ibuf= NULL;
+
+       ob = OBACT;
+       if (!ob) {
+               error("No active object"); return;
+       }
+       if (!(ob->lay & G.vd->lay)) {
+               error("The active object is not in this layer"); return;
        }
+       me = get_mesh(ob);
+       if (!me) {
+               error("The active object does not have a mesh obData"); return;
+       }
+
+       brush = imapaint_brush_new(Gvp.size, Gvp.size, &Gvp.r, Gvp.a, 0.5);
+       if (!brush) {
+               error("Can't create brush"); return;
+       }
+
+       persp(PERSP_VIEW);
+
+       if (U.flag & USER_LMOUSESELECT) mousebutton = R_MOUSE;
+       else mousebutton = L_MOUSE;
+
+       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;
+                                       ibuf = (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) {
+                                               face_pick_uv(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) {
+                                                       /* 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) {
+                                                               face_pick_uv(ob, me, face, xy_old, uv_old);
+                                                               face_pick_uv(ob, me, face, xy, uv);
+                                                               imapaint_blend_line(canvas, brush, uv_old, uv);
+                                                               ibuf->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) {
+                                                       face_pick_uv(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) {
+                                                       face_pick_uv(ob, me, face, xy_old, uv_old);
+                                                       face_pick_uv(ob, me, face, xy, uv);
+                                                       imapaint_blend_line(canvas, brush, uv_old, uv);
+                                                       ibuf->userflags |= IB_BITMAPDIRTY;
+                                               }
+                                       }
+                               }
+                       }
+                       else {
+                               /* Same face, continue drawing */
+                               if (face && canvas) {
+                                       /* Get the new (u,v) coordinates */
+                                       face_pick_uv(ob, me, face, xy, uv);
+                                       imapaint_blend_line(canvas, brush, uv_old, uv);
+                                       ibuf->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;
+               }
+       }
+
+       imapaint_brush_free(brush);
+       if (canvas) {
+               imapaint_pixmap_free(canvas);
+               canvas = 0;
+       }
+
+       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);
 }
 
index 235c9bcea4ba99eefa1e6c454659f7a82a0b6417..538f664663d6e542f8a41e679da9e8efcc428827 100644 (file)
 #include "BKE_depsgraph.h"
 
 #include "BSE_trans_types.h"
-#include "IMG_Api.h"
 
 #include "SYS_System.h" /* for the user def menu ... should move elsewhere. */
 
@@ -1012,7 +1011,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                        vertex_paint();
                                }
                                else if (G.f & G_TEXTUREPAINT) {
-                                       face_draw();
+                                       texturepaint_paint();
                                }
                                break;
                        case MIDDLEMOUSE:
index 70ec992917cd496c4962599a2c1d77bb006388b8..9920c2a509ba406ca335cbedb280581d9a0f3bba 100644 (file)
@@ -80,7 +80,6 @@ endif
     export NAN_MEMUTIL ?= $(LCGDIR)/memutil
     export NAN_CONTAINER ?= $(LCGDIR)/container
     export NAN_ACTION ?= $(LCGDIR)/action
-    export NAN_IMG ?= $(LCGDIR)/img
     export NAN_GHOST ?= $(LCGDIR)/ghost
     export NAN_TEST_VERBOSITY ?= 1
     export NAN_BMFONT ?= $(LCGDIR)/bmfont