Texture paint refactoring commit
authorAntony Riakiotakis <kalast@gmail.com>
Thu, 7 Mar 2013 12:11:38 +0000 (12:11 +0000)
committerAntony Riakiotakis <kalast@gmail.com>
Thu, 7 Mar 2013 12:11:38 +0000 (12:11 +0000)
This is as close as I can get to keeping the old code intact. After this
commit, I will have to change existing code paths, making testing of
functionality harder.

Changes:

* Keep only projective texturing code in paint_image_proj.c
* Move 2D code to paint_image_2d.c. This needed the introduction of
allocation/cleanup functions for the relevant structures.
* Common code interface for both modes stays in paint_image.c (which
still includes all old code, system should work as it did with the
exception of non-projective 3D paint mode) and is made public. This is
not a lot of code, only rectangle invalidation and undo system.
* Changed the naming in the new code slightly: imapaint_ prefixed functions refer to
common functions used by both systems, paint_2d_ prefixed to 2d
painting. There will be an interface for the projection painting as
well. Probably there is some leftover naming conversions to do.

TODO:

* Move operator init/exec/modal to common interface file
* Get rid of old BKE_brush_painter_paint, now brush_painter_2d_paint.
All code uses stroke system for the stroke management
* Write space pressure management for the paint stroke system (for other
systems to access as well :) )
* Move texture paint tablet presssure exception code for old bugs to
stroke system (makes me wonder...aren't other systems also influenced by
these pressure issues?) or up in the function hierarchy inside texture
paint. This code is still not there so users with tablets may notice
some issues.
* possibly change other systems to pre-multiply pressure with the
relevant influenced attributes in the stroke function. This could get
tricky though and it's possible that it could backfire.

source/blender/blenkernel/BKE_brush.h
source/blender/blenkernel/BKE_paint.h
source/blender/blenkernel/intern/brush.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_image_2d.c
source/blender/editors/sculpt_paint/paint_image_proj.c
source/blender/editors/sculpt_paint/paint_intern.h
source/blender/editors/sculpt_paint/paint_stroke.c

index cfae159..95c39ba 100644 (file)
@@ -79,13 +79,13 @@ struct BrushPainter;
 typedef struct BrushPainter BrushPainter;
 typedef int (*BrushFunc)(void *user, struct ImBuf *ibuf, const float lastpos[2], const float pos[2]);
 
-BrushPainter *BKE_brush_painter_new(struct Scene *scene, struct Brush *brush);
-void BKE_brush_painter_require_imbuf(BrushPainter *painter, short flt,
+BrushPainter *brush_painter_2d_new(struct Scene *scene, struct Brush *brush);
+void brush_painter_2d_require_imbuf(BrushPainter *painter, short flt,
                                      short texonly, int size);
-int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float pos[2],
+int brush_painter_2d_paint(BrushPainter *painter, BrushFunc func, const float pos[2],
                             double time, float pressure, void *user, int use_color_correction);
-void BKE_brush_painter_break_stroke(BrushPainter *painter);
-void BKE_brush_painter_free(BrushPainter *painter);
+void brush_painter_2d_break_stroke(BrushPainter *painter);
+void brush_painter_2d_free(BrushPainter *painter);
 
 /* texture */
 unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side);
index 98184bf..c46bc1d 100644 (file)
@@ -54,7 +54,7 @@ extern const char PAINT_CURSOR_VERTEX_PAINT[3];
 extern const char PAINT_CURSOR_WEIGHT_PAINT[3];
 extern const char PAINT_CURSOR_TEXTURE_PAINT[3];
 
-typedef enum {
+typedef enum PaintMode{
        PAINT_SCULPT,
        PAINT_VERTEX,
        PAINT_WEIGHT,
index ba69fa4..798dde9 100644 (file)
@@ -53,6 +53,7 @@
 #include "IMB_imbuf_types.h"
 
 #include "RE_render_ext.h" /* externtex */
+#include "RE_shader_ext.h"
 
 static void brush_defaults(Brush *brush)
 {
@@ -841,6 +842,49 @@ float BKE_brush_curve_strength(Brush *br, float p, const float len)
        return curvemapping_evaluateF(br->curve, 0, p);
 }
 
+/* TODO: should probably be unified with BrushPainter stuff? */
+unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side)
+{
+       unsigned int *texcache = NULL;
+       MTex *mtex = &br->mtex;
+       TexResult texres = {0};
+       int hasrgb, ix, iy;
+       int side = half_side * 2;
+
+       if (mtex->tex) {
+               float x, y, step = 2.0 / side, co[3];
+
+               texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache");
+
+               /*do normalized cannonical view coords for texture*/
+               for (y = -1.0, iy = 0; iy < side; iy++, y += step) {
+                       for (x = -1.0, ix = 0; ix < side; ix++, x += step) {
+                               co[0] = x;
+                               co[1] = y;
+                               co[2] = 0.0f;
+
+                               /* This is copied from displace modifier code */
+                               hasrgb = multitex_ext(mtex->tex, co, NULL, NULL, 0, &texres, NULL);
+
+                               /* if the texture gave an RGB value, we assume it didn't give a valid
+                                * intensity, so calculate one (formula from do_material_tex).
+                                * if the texture didn't give an RGB value, copy the intensity across
+                                */
+                               if (hasrgb & TEX_RGB)
+                                       texres.tin = rgb_to_grayscale(&texres.tr);
+
+                               ((char *)texcache)[(iy * side + ix) * 4] =
+                               ((char *)texcache)[(iy * side + ix) * 4 + 1] =
+                               ((char *)texcache)[(iy * side + ix) * 4 + 2] =
+                               ((char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(texres.tin * 255.0f);
+                       }
+               }
+       }
+
+       return texcache;
+}
+
+
 /**** Radial Control ****/
 struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br)
 {
index 63a111c..87f0820 100644 (file)
@@ -140,9 +140,6 @@ BLI_INLINE unsigned char f_to_char(const float val)
 #define IMAPAINT_TILE_SIZE          (1 << IMAPAINT_TILE_BITS)
 #define IMAPAINT_TILE_NUMBER(size)  (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
 
-static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint);
-
-
 typedef struct ImagePaintState {
        SpaceImage *sima;
        View2D *v2d;
@@ -171,11 +168,6 @@ typedef struct ImagePaintState {
        MTFace         *dm_mtface;
 } ImagePaintState;
 
-typedef struct ImagePaintPartialRedraw {
-       int x1, y1, x2, y2;  /* XXX, could use 'rcti' */
-       int enabled;
-} ImagePaintPartialRedraw;
-
 typedef struct ImagePaintRegion {
        int destx, desty;
        int srcx, srcy;
@@ -411,8 +403,19 @@ typedef struct UndoImageTile {
        char gen_type;
 } UndoImageTile;
 
+/* this is a static resource for non-globality,
+ * Maybe it should be exposed as part of the
+ * paint operation, but for now just give a public interface */
 static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
 
+ImagePaintPartialRedraw *get_imapaintpartial(void) {
+       return &imapaintpartial;
+}
+
+void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr) {
+       imapaintpartial = *ippr;
+}
+
 /* UNDO */
 
 static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore)
@@ -433,7 +436,7 @@ static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int
                            tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
 }
 
-static void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
+void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
 {
        ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
        UndoImageTile *tile;
@@ -4349,7 +4352,7 @@ static int project_paint_sub_stroke(ProjPaintState *ps, BrushPainter *painter, c
        // we may want to use this later 
        // BKE_brush_painter_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0, 0);
        
-       if (BKE_brush_painter_paint(painter, project_paint_op, pos, time, pressure, ps, 0)) {
+       if (brush_painter_2d_paint(painter, project_paint_op, pos, time, pressure, ps, 0)) {
                return 1;
        }
        else return 0;
@@ -4373,12 +4376,12 @@ static int project_paint_stroke(ProjPaintState *ps, BrushPainter *painter, const
 
 /* Imagepaint Partial Redraw & Dirty Region */
 
-static void imapaint_clear_partial_redraw(void)
+void imapaint_clear_partial_redraw(void)
 {
        memset(&imapaintpartial, 0, sizeof(imapaintpartial));
 }
 
-static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
+void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
 {
        ImBuf *tmpibuf = NULL;
        int srcx = 0, srcy = 0, origx;
@@ -4417,7 +4420,7 @@ static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w,
                IMB_freeImBuf(tmpibuf);
 }
 
-static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint)
+void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint)
 {
        if (imapaintpartial.x1 != imapaintpartial.x2 &&
            imapaintpartial.y1 != imapaintpartial.y2)
@@ -4717,7 +4720,7 @@ static int texpaint_break_stroke(float *prevuv, float *fwuv, float *bkuv, float
 static int imapaint_canvas_set(ImagePaintState *s, Image *ima)
 {
        ImBuf *ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
-       
+
        /* verify that we can paint and set canvas */
        if (ima == NULL) {
                return 0;
@@ -4740,7 +4743,7 @@ static int imapaint_canvas_set(ImagePaintState *s, Image *ima)
        if (s->tool == PAINT_TOOL_CLONE) {
                ima = s->brush->clone.image;
                ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
-               
+
                if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
                        BKE_image_release_ibuf(ima, ibuf, NULL);
                        BKE_image_release_ibuf(s->image, s->canvas, NULL);
@@ -4780,12 +4783,12 @@ static int imapaint_paint_sub_stroke(ImagePaintState *s, BrushPainter *painter,
        pos[0] = uv[0] * ibuf->x;
        pos[1] = uv[1] * ibuf->y;
 
-       BKE_brush_painter_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0, 0);
+       brush_painter_2d_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0, 0);
 
        /* OCIO_TODO: float buffers are now always linear, so always use color correction
         *            this should probably be changed when texture painting color space is supported
         */
-       if (BKE_brush_painter_paint(painter, imapaint_paint_op, pos, time, pressure, s, is_data == FALSE)) {
+       if (brush_painter_2d_paint(painter, imapaint_paint_op, pos, time, pressure, s, is_data == FALSE)) {
                if (update)
                        imapaint_image_update(s->sima, image, ibuf, texpaint);
                BKE_image_release_ibuf(image, ibuf, NULL);
@@ -4844,7 +4847,7 @@ static int imapaint_paint_stroke(ViewContext *vc, ImagePaintState *s, BrushPaint
                        redraw |= imapaint_paint_sub_stroke(s, painter, s->image, texpaint,
                                                            fwuv, time, 1, pressure);
                        imapaint_clear_partial_redraw();
-                       BKE_brush_painter_break_stroke(painter);
+                       brush_painter_2d_break_stroke(painter);
                }
 
                /* set new canvas */
@@ -5044,7 +5047,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps)
                ps->do_mask_normal = FALSE;  /* no need to do blending */
 }
 
-static void paint_brush_init_tex(Brush *brush)
+void paint_brush_init_tex(Brush *brush)
 {
        /* init mtex nodes */ 
        if (brush) {
@@ -5167,7 +5170,7 @@ static int texture_paint_init(bContext *C, wmOperator *op)
                              image_undo_restore, image_undo_free);
 
        /* create painter */
-       pop->painter = BKE_brush_painter_new(scene, pop->s.brush);
+       pop->painter = brush_painter_2d_new(scene, pop->s.brush);
 
        {
                UnifiedPaintSettings *ups = &settings->unified_paint_settings;
@@ -5214,7 +5217,7 @@ static void paint_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
        pop->first = 0;
 }
 
-static void paint_brush_exit_tex(Brush *brush)
+void paint_brush_exit_tex(Brush *brush)
 {
        if (brush) {
                MTex *mtex = &brush->mtex;
@@ -5234,7 +5237,7 @@ static void paint_exit(bContext *C, wmOperator *op)
 
        settings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
        imapaint_canvas_free(&pop->s);
-       BKE_brush_painter_free(pop->painter);
+       brush_painter_2d_free(pop->painter);
 
        if (pop->mode == PAINT_MODE_3D_PROJECT) {
                BKE_brush_size_set(scene, pop->ps.brush, pop->orig_brush_size);
index 8425085..194b36a 100644 (file)
 
 #include "DNA_brush_types.h"
 #include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_object_types.h"
 
+#include "BKE_context.h"
 #include "BKE_brush.h"
+#include "BKE_main.h"
+#include "BKE_image.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
+
+#include "ED_screen.h"
 
 #include "BLI_math.h"
 
 #include "IMB_imbuf.h"
 #include "IMB_imbuf_types.h"
+#include "IMB_colormanagement.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_view2d.h"
 
 #include "RE_shader_ext.h"
 
- /* Brush Painting for 2D image editor */
+#include "GPU_draw.h"
+
+#include "paint_intern.h"
+
+/* Brush Painting for 2D image editor */
+
+/* Defines and Structs */
+/* FTOCHAR as inline function */
+BLI_INLINE unsigned char f_to_char(const float val)
+{
+       return FTOCHAR(val);
+}
+#define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f)  {                                   \
+       (c)[0] = f_to_char((f)[0]);                                               \
+       (c)[1] = f_to_char((f)[1]);                                               \
+       (c)[2] = f_to_char((f)[2]);                                               \
+} (void)0
+
+#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]);                                   \
+} (void)0
+
+#define IMAPAINT_FLOAT_RGB_COPY(a, b) copy_v3_v3(a, b)
+
+typedef struct ImagePaintRegion {
+       int destx, desty;
+       int srcx, srcy;
+       int width, height;
+} ImagePaintRegion;
+
+typedef struct ImagePaintState {
+       BrushPainter *painter;
+       SpaceImage *sima;
+       View2D *v2d;
+       Scene *scene;
+       bScreen *screen;
+
+       Brush *brush;
+       short tool, blend;
+       Image *image;
+       ImBuf *canvas;
+       ImBuf *clonecanvas;
+       char *warnpackedfile;
+       char *warnmultifile;
+
+       /* viewport texture paint only, but _not_ project paint */
+       Object *ob;
+       int faceindex;
+       float uv[2];
+       int do_facesel;
+} ImagePaintState;
 
 typedef struct BrushPainterCache {
        short enabled;
@@ -88,7 +155,7 @@ struct BrushPainter {
        BrushPainterCache cache;
 };
 
-BrushPainter *BKE_brush_painter_new(Scene *scene, Brush *brush)
+BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush)
 {
        BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter");
 
@@ -119,7 +186,7 @@ static void brush_pressure_apply(BrushPainter *painter, Brush *brush, float pres
 }
 
 
-void BKE_brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size)
+void brush_painter_2d_require_imbuf(BrushPainter *painter, short flt, short texonly, int size)
 {
        if ((painter->cache.flt != flt) || (painter->cache.size != size) ||
            ((painter->cache.texonly != texonly) && texonly))
@@ -142,7 +209,7 @@ void BKE_brush_painter_require_imbuf(BrushPainter *painter, short flt, short tex
        painter->cache.enabled = 1;
 }
 
-void BKE_brush_painter_free(BrushPainter *painter)
+void brush_painter_2d_free(BrushPainter *painter)
 {
        Brush *brush = painter->brush;
 
@@ -157,7 +224,7 @@ void BKE_brush_painter_free(BrushPainter *painter)
        MEM_freeN(painter);
 }
 
-static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf,
+static void brush_painter_2d_do_partial(BrushPainter *painter, ImBuf *oldtexibuf,
                                      int x, int y, int w, int h, int xt, int yt,
                                      const float pos[2])
 {
@@ -248,7 +315,7 @@ static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf,
        }
 }
 
-static void brush_painter_tiled_tex_partial_update(BrushPainter *painter, const float pos[2])
+static void brush_painter_2d_tiled_tex_partial_update(BrushPainter *painter, const float pos[2])
 {
        const Scene *scene = painter->scene;
        Brush *brush = painter->brush;
@@ -286,23 +353,23 @@ static void brush_painter_tiled_tex_partial_update(BrushPainter *painter, const
 
        /* blend existing texture in new position */
        if ((x1 < x2) && (y1 < y2))
-               brush_painter_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos);
+               brush_painter_2d_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos);
 
        if (oldtexibuf)
                IMB_freeImBuf(oldtexibuf);
 
        /* sample texture in new areas */
        if ((0 < x1) && (0 < ibuf->y))
-               brush_painter_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos);
+               brush_painter_2d_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos);
        if ((x2 < ibuf->x) && (0 < ibuf->y))
-               brush_painter_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos);
+               brush_painter_2d_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos);
        if ((x1 < x2) && (0 < y1))
-               brush_painter_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos);
+               brush_painter_2d_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos);
        if ((x1 < x2) && (y2 < ibuf->y))
-               brush_painter_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos);
+               brush_painter_2d_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos);
 }
 
-static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2], int use_color_correction)
+static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float pos[2], int use_color_correction)
 {
        const Scene *scene = painter->scene;
        Brush *brush = painter->brush;
@@ -332,7 +399,7 @@ static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2
 
                if (do_tiled) {
                        BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf, use_color_correction);
-                       brush_painter_tiled_tex_partial_update(painter, pos);
+                       brush_painter_2d_tiled_tex_partial_update(painter, pos);
                }
                else
                        BKE_brush_imbuf_new(scene, brush, flt, 2, size, &cache->ibuf, use_color_correction);
@@ -346,17 +413,17 @@ static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2
                int dy = (int)painter->lastpaintpos[1] - (int)pos[1];
 
                if ((dx != 0) || (dy != 0))
-                       brush_painter_tiled_tex_partial_update(painter, pos);
+                       brush_painter_2d_tiled_tex_partial_update(painter, pos);
        }
 }
 
-void BKE_brush_painter_break_stroke(BrushPainter *painter)
+void brush_painter_2d_break_stroke(BrushPainter *painter)
 {
        painter->firsttouch = 1;
 }
 
 
-int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float pos[2], double time, float pressure,
+int brush_painter_2d_paint(BrushPainter *painter, BrushFunc func, const float pos[2], double time, float pressure,
                             void *user, int use_color_correction)
 {
        Scene *scene = painter->scene;
@@ -376,7 +443,7 @@ int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float p
 
                brush_pressure_apply(painter, brush, pressure);
                if (painter->cache.enabled)
-                       brush_painter_refresh_cache(painter, pos, use_color_correction);
+                       brush_painter_2d_refresh_cache(painter, pos, use_color_correction);
                totpaintops += func(user, painter->cache.ibuf, pos, pos);
                
                painter->lasttime = time;
@@ -449,7 +516,7 @@ int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float p
                                BKE_brush_jitter_pos(scene, brush, paintpos, finalpos);
 
                                if (painter->cache.enabled)
-                                       brush_painter_refresh_cache(painter, finalpos, use_color_correction);
+                                       brush_painter_2d_refresh_cache(painter, finalpos, use_color_correction);
 
                                totpaintops +=
                                    func(user, painter->cache.ibuf, painter->lastpaintpos, finalpos);
@@ -464,7 +531,7 @@ int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float p
                        BKE_brush_jitter_pos(scene, brush, pos, finalpos);
 
                        if (painter->cache.enabled)
-                               brush_painter_refresh_cache(painter, finalpos, use_color_correction);
+                               brush_painter_2d_refresh_cache(painter, finalpos, use_color_correction);
 
                        totpaintops += func(user, painter->cache.ibuf, pos, finalpos);
 
@@ -492,7 +559,7 @@ int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float p
                                BKE_brush_jitter_pos(scene, brush, pos, finalpos);
 
                                if (painter->cache.enabled)
-                                       brush_painter_refresh_cache(painter, finalpos, use_color_correction);
+                                       brush_painter_2d_refresh_cache(painter, finalpos, use_color_correction);
 
                                totpaintops +=
                                    func(user, painter->cache.ibuf, painter->lastmousepos, finalpos);
@@ -515,46 +582,428 @@ int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float p
        return totpaintops;
 }
 
+/* Image Paint Operations */
 
-/* TODO: should probably be unified with BrushPainter stuff? */
-unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side)
+/* keep these functions in sync */
+static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, const short is_torus, float r_rgb[3])
 {
-       unsigned int *texcache = NULL;
-       MTex *mtex = &br->mtex;
-       TexResult texres = {0};
-       int hasrgb, ix, iy;
-       int side = half_side * 2;
-       
-       if (mtex->tex) {
-               float x, y, step = 2.0 / side, co[3];
-
-               texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache");
-
-               /*do normalized cannonical view coords for texture*/
-               for (y = -1.0, iy = 0; iy < side; iy++, y += step) {
-                       for (x = -1.0, ix = 0; ix < side; ix++, x += step) {
-                               co[0] = x;
-                               co[1] = y;
-                               co[2] = 0.0f;
-                               
-                               /* This is copied from displace modifier code */
-                               hasrgb = multitex_ext(mtex->tex, co, NULL, NULL, 0, &texres, NULL);
-                       
-                               /* if the texture gave an RGB value, we assume it didn't give a valid
-                                * intensity, so calculate one (formula from do_material_tex).
-                                * if the texture didn't give an RGB value, copy the intensity across
-                                */
-                               if (hasrgb & TEX_RGB)
-                                       texres.tin = rgb_to_grayscale(&texres.tr);
-
-                               ((char *)texcache)[(iy * side + ix) * 4] =
-                               ((char *)texcache)[(iy * side + ix) * 4 + 1] =
-                               ((char *)texcache)[(iy * side + ix) * 4 + 2] =
-                               ((char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(texres.tin * 255.0f);
-                       }
+       if (is_torus) {
+               x %= ibuf->x;
+               if (x < 0) x += ibuf->x;
+               y %= ibuf->y;
+               if (y < 0) y += ibuf->y;
+       }
+
+       if (ibuf->rect_float) {
+               float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
+               IMAPAINT_FLOAT_RGB_COPY(r_rgb, rrgbf);
+       }
+       else {
+               char *rrgb = (char *)ibuf->rect + (ibuf->x * y + x) * 4;
+               IMAPAINT_CHAR_RGB_TO_FLOAT(r_rgb, rrgb);
+       }
+}
+static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const short is_torus, const float rgb[3])
+{
+       if (is_torus) {
+               x %= ibuf->x;
+               if (x < 0) x += ibuf->x;
+               y %= ibuf->y;
+               if (y < 0) y += ibuf->y;
+       }
+
+       if (ibuf->rect_float) {
+               float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
+               IMAPAINT_FLOAT_RGB_COPY(rrgbf, rgb);
+       }
+       else {
+               char *rrgb = (char *)ibuf->rect + (ibuf->x * y + x) * 4;
+               IMAPAINT_FLOAT_RGB_TO_CHAR(rrgb, rgb);
+       }
+}
+
+static int paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus)
+{
+       float inrgb[3];
+
+       // XXX: signed unsigned mismatch
+       if ((x >= (unsigned int)(ibuf->x)) || (y >= (unsigned int)(ibuf->y))) {
+               if (torus) paint_2d_ibuf_rgb_get(ibuf, x, y, 1, inrgb);
+               else return 0;
+       }
+       else {
+               paint_2d_ibuf_rgb_get(ibuf, x, y, 0, inrgb);
+       }
+
+       outrgb[0] += inrgb[0];
+       outrgb[1] += inrgb[1];
+       outrgb[2] += inrgb[2];
+
+       return 1;
+}
+
+static void paint_2d_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const short is_torus)
+{
+       int x, y, count, xi, yi, xo, yo;
+       int out_off[2], in_off[2], dim[2];
+       float outrgb[3];
+
+       dim[0] = ibufb->x;
+       dim[1] = ibufb->y;
+       in_off[0] = pos[0];
+       in_off[1] = pos[1];
+       out_off[0] = out_off[1] = 0;
+
+       if (!is_torus) {
+               IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
+                            &out_off[1], &dim[0], &dim[1]);
+
+               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;
+
+                       count = 1;
+                       paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, outrgb);
+
+                       count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi - 1, outrgb, is_torus);
+                       count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi, outrgb, is_torus);
+                       count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi + 1, outrgb, is_torus);
+
+                       count += paint_2d_ibuf_add_if(ibuf, xi, yi - 1, outrgb, is_torus);
+                       count += paint_2d_ibuf_add_if(ibuf, xi, yi + 1, outrgb, is_torus);
+
+                       count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi - 1, outrgb, is_torus);
+                       count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi, outrgb, is_torus);
+                       count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi + 1, outrgb, is_torus);
+
+                       mul_v3_fl(outrgb, 1.0f / (float)count);
+
+                       /* write into brush buffer */
+                       xo = out_off[0] + x;
+                       yo = out_off[1] + y;
+                       paint_2d_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb);
+               }
+       }
+}
+
+static void paint_2d_set_region(ImagePaintRegion *region, int destx, int desty, int srcx, int srcy, int width, int height)
+{
+       region->destx = destx;
+       region->desty = desty;
+       region->srcx = srcx;
+       region->srcy = srcy;
+       region->width = width;
+       region->height = height;
+}
+
+static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf)
+{
+       int destx = region->destx;
+       int desty = region->desty;
+       int srcx = region->srcx;
+       int srcy = region->srcy;
+       int width = region->width;
+       int height = region->height;
+       int origw, origh, w, h, tot = 0;
+
+       /* convert destination and source coordinates to be within image */
+       destx = destx % dbuf->x;
+       if (destx < 0) destx += dbuf->x;
+       desty = desty % dbuf->y;
+       if (desty < 0) desty += dbuf->y;
+       srcx = srcx % sbuf->x;
+       if (srcx < 0) srcx += sbuf->x;
+       srcy = srcy % sbuf->y;
+       if (srcy < 0) srcy += sbuf->y;
+
+       /* clip width of blending area to destination imbuf, to avoid writing the
+        * same pixel twice */
+       origw = w = (width > dbuf->x) ? dbuf->x : width;
+       origh = h = (height > dbuf->y) ? dbuf->y : height;
+
+       /* clip within image */
+       IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h);
+       paint_2d_set_region(&region[tot++], destx, desty, srcx, srcy, w, h);
+
+       /* do 3 other rects if needed */
+       if (w < origw)
+               paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h);
+       if (h < origh)
+               paint_2d_set_region(&region[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h);
+       if ((w < origw) && (h < origh))
+               paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, (desty + h) % dbuf->y, (srcx + w) % sbuf->x, (srcy + h) % sbuf->y, origw - w, origh - h);
+
+       return tot;
+}
+
+static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos)
+{
+       ImagePaintRegion region[4];
+       int a, tot;
+
+       paint_2d_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y);
+       tot = paint_2d_torus_split_region(region, ibufb, ibuf);
+
+       for (a = 0; a < tot; a++)
+               IMB_rectblend(ibufb, ibuf, region[a].destx, region[a].desty,
+                             region[a].srcx, region[a].srcy,
+                             region[a].width, region[a].height, IMB_BLEND_COPY_RGB);
+}
+
+static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
+{
+       /* note: allocImbuf returns zero'd memory, so regions outside image will
+        * have zero alpha, and hence not be blended onto the image */
+       int w = ibufb->x, h = ibufb->y, destx = 0, desty = 0, srcx = pos[0], srcy = pos[1];
+       ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
+
+       IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
+       IMB_rectblend(clonebuf, ibuf, destx, desty, srcx, srcy, w, h,
+                     IMB_BLEND_COPY_RGB);
+       IMB_rectblend(clonebuf, ibufb, destx, desty, destx, desty, w, h,
+                     IMB_BLEND_COPY_ALPHA);
+
+       return clonebuf;
+}
+
+static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[2])
+{
+       ipos[0] = (int)floorf((pos[0] - ibufb->x / 2) + 1.0f);
+       ipos[1] = (int)floorf((pos[1] - ibufb->y / 2) + 1.0f);
+}
+
+static int paint_2d_op(void *state, ImBuf *ibufb, const float lastpos[2], const float pos[2])
+{
+       ImagePaintState *s = ((ImagePaintState *)state);
+       ImBuf *clonebuf = NULL, *frombuf;
+       ImagePaintRegion region[4];
+       short torus = s->brush->flag & BRUSH_TORUS;
+       short blend = s->blend;
+       float *offset = s->brush->clone.offset;
+       float liftpos[2];
+       int bpos[2], blastpos[2], bliftpos[2];
+       int a, tot;
+
+       paint_2d_convert_brushco(ibufb, pos, bpos);
+
+       /* lift from canvas */
+       if (s->tool == PAINT_TOOL_SOFTEN) {
+               paint_2d_lift_soften(s->canvas, ibufb, bpos, torus);
+       }
+       else if (s->tool == PAINT_TOOL_SMEAR) {
+               if (lastpos[0] == pos[0] && lastpos[1] == pos[1])
+                       return 0;
+
+               paint_2d_convert_brushco(ibufb, lastpos, blastpos);
+               paint_2d_lift_smear(s->canvas, ibufb, blastpos);
+       }
+       else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
+               liftpos[0] = pos[0] - offset[0] * s->canvas->x;
+               liftpos[1] = pos[1] - offset[1] * s->canvas->y;
+
+               paint_2d_convert_brushco(ibufb, liftpos, bliftpos);
+               clonebuf = paint_2d_lift_clone(s->clonecanvas, ibufb, bliftpos);
+       }
+
+       frombuf = (clonebuf) ? clonebuf : ibufb;
+
+       if (torus) {
+               paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
+               tot = paint_2d_torus_split_region(region, s->canvas, frombuf);
+       }
+       else {
+               paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
+               tot = 1;
+       }
+
+       /* blend into canvas */
+       for (a = 0; a < tot; a++) {
+               imapaint_dirty_region(s->image, s->canvas,
+                                     region[a].destx, region[a].desty,
+                                     region[a].width, region[a].height);
+
+               IMB_rectblend(s->canvas, frombuf,
+                             region[a].destx, region[a].desty,
+                             region[a].srcx, region[a].srcy,
+                             region[a].width, region[a].height, blend);
+       }
+
+       if (clonebuf) IMB_freeImBuf(clonebuf);
+
+       return 1;
+}
+
+
+static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
+{
+       ImBuf *ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
+
+       /* verify that we can paint and set canvas */
+       if (ima == NULL) {
+               return 0;
+       }
+       else if (ima->packedfile && ima->rr) {
+               s->warnpackedfile = ima->id.name + 2;
+               return 0;
+       }
+       else if (ibuf && ibuf->channels != 4) {
+               s->warnmultifile = ima->id.name + 2;
+               return 0;
+       }
+       else if (!ibuf || !(ibuf->rect || ibuf->rect_float))
+               return 0;
+
+       s->image = ima;
+       s->canvas = ibuf;
+
+       /* set clone canvas */
+       if (s->tool == PAINT_TOOL_CLONE) {
+               ima = s->brush->clone.image;
+               ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
+
+               if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
+                       BKE_image_release_ibuf(ima, ibuf, NULL);
+                       BKE_image_release_ibuf(s->image, s->canvas, NULL);
+                       return 0;
                }
+
+               s->clonecanvas = ibuf;
+
+               /* temporarily add float rect for cloning */
+               if (s->canvas->rect_float && !s->clonecanvas->rect_float) {
+                       IMB_float_from_rect(s->clonecanvas);
+               }
+               else if (!s->canvas->rect_float && !s->clonecanvas->rect)
+                       IMB_rect_from_float(s->clonecanvas);
+       }
+
+       return 1;
+}
+
+static void paint_2d_canvas_free(ImagePaintState *s)
+{
+       BKE_image_release_ibuf(s->image, s->canvas, NULL);
+       BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL);
+}
+
+static int paint_2d_sub_stroke(ImagePaintState *s, BrushPainter *painter, Image *image, float *uv, int update, float pressure)
+{
+       ImBuf *ibuf = BKE_image_acquire_ibuf(image, s->sima ? &s->sima->iuser : NULL, NULL);
+       float pos[2];
+       int is_data;
+
+       if (!ibuf)
+               return 0;
+
+       is_data = ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA;
+
+       pos[0] = uv[0] * ibuf->x;
+       pos[1] = uv[1] * ibuf->y;
+
+       brush_painter_2d_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0, 0);
+
+       /* OCIO_TODO: float buffers are now always linear, so always use color correction
+        *            this should probably be changed when texture painting color space is supported
+        */
+       if (brush_painter_2d_paint(painter, paint_2d_op, pos, 0, pressure, s, is_data == FALSE)) {
+               if (update)
+                       imapaint_image_update(s->sima, image, ibuf, false);
+               BKE_image_release_ibuf(image, ibuf, NULL);
+               return 1;
        }
+       else {
+               BKE_image_release_ibuf(image, ibuf, NULL);
+               return 0;
+       }
+}
+
+int paint_2d_stroke(void *ps, const int mval[2], float pressure, int eraser)
+{
+       float newuv[2];
+       int redraw = 0;
+       ImagePaintState *s = ps;
+       BrushPainter *painter = s->painter;
 
-       return texcache;
+       s->blend = s->brush->blend;
+       if (eraser)
+               s->blend = IMB_BLEND_ERASE_ALPHA;
+
+       UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &newuv[0], &newuv[1]);
+       redraw |= paint_2d_sub_stroke(s, painter, s->image, newuv,
+                                                   1, pressure);
+
+       if (redraw)
+               imapaint_clear_partial_redraw();
+
+       return redraw;
 }
 
+void *paint_2d_new_stroke(bContext *C, wmOperator *op) {
+       Scene *scene = CTX_data_scene(C);
+       ToolSettings *settings = scene->toolsettings;
+       Brush *brush = paint_brush(&settings->imapaint.paint);
+
+       ImagePaintState *s = MEM_callocN(sizeof(ImagePaintState), "ImagePaintState");
+
+       s->sima = CTX_wm_space_image(C);
+       s->v2d = &CTX_wm_region(C)->v2d;
+       s->scene = scene;
+       s->screen = CTX_wm_screen(C);
+
+       s->brush = brush;
+       s->tool = brush->imagepaint_tool;
+       s->blend = brush->blend;
+
+       s->image = s->sima->image;
+
+       if (!paint_2d_canvas_set(s, s->image)) {
+               if (s->warnmultifile)
+                       BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint");
+               if (s->warnpackedfile)
+                       BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted");
+
+               MEM_freeN(s);
+               return NULL;
+       }
+
+       paint_brush_init_tex(s->brush);
+
+       /* create painter */
+       s->painter = brush_painter_2d_new(scene, s->brush);
+
+       return s;
+}
+
+void paint_2d_redraw (const bContext *C, void *ps, int final) {
+       ImagePaintState *s = ps;
+
+       if (final) {
+               if (s->image && !(s->sima && s->sima->lock))
+                       GPU_free_image(s->image);
+
+               /* compositor listener deals with updating */
+               WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
+       }
+       else {
+               if (!s->sima || !s->sima->lock)
+                       ED_region_tag_redraw(CTX_wm_region(C));
+               else
+                       WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
+       }
+}
+
+void paint_2d_stroke_done(void *ps) {
+       ImagePaintState *s = ps;
+
+       paint_2d_canvas_free(s);
+       brush_painter_2d_free(s->painter);
+       paint_brush_exit_tex(s->brush);
+
+       MEM_freeN(s);
+}
index 69383d7..e594bf2 100644 (file)
@@ -108,25 +108,13 @@ BLI_INLINE unsigned char f_to_char(const float val)
        return FTOCHAR(val);
 }
 
-
-#define IMAPAINT_CHAR_TO_FLOAT(c) ((c) / 255.0f)
-
-#define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f)  {                                   \
-       (c)[0] = f_to_char((f)[0]);                                               \
-       (c)[1] = f_to_char((f)[1]);                                               \
-       (c)[2] = f_to_char((f)[2]);                                               \
-} (void)0
 #define IMAPAINT_FLOAT_RGBA_TO_CHAR(c, f)  {                                  \
        (c)[0] = f_to_char((f)[0]);                                               \
        (c)[1] = f_to_char((f)[1]);                                               \
        (c)[2] = f_to_char((f)[2]);                                               \
        (c)[3] = f_to_char((f)[3]);                                               \
 } (void)0
-#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]);                                   \
-} (void)0
+
 #define IMAPAINT_CHAR_RGBA_TO_FLOAT(f, c)  {                                  \
        (f)[0] = IMAPAINT_CHAR_TO_FLOAT((c)[0]);                                   \
        (f)[1] = IMAPAINT_CHAR_TO_FLOAT((c)[1]);                                   \
@@ -134,53 +122,11 @@ BLI_INLINE unsigned char f_to_char(const float val)
        (f)[3] = IMAPAINT_CHAR_TO_FLOAT((c)[3]);                                   \
 } (void)0
 
-#define IMAPAINT_FLOAT_RGB_COPY(a, b) copy_v3_v3(a, b)
-
-#define IMAPAINT_TILE_BITS          6
-#define IMAPAINT_TILE_SIZE          (1 << IMAPAINT_TILE_BITS)
-#define IMAPAINT_TILE_NUMBER(size)  (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
-
-static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint);
-
-
-typedef struct ImagePaintState {
-       SpaceImage *sima;
-       View2D *v2d;
-       Scene *scene;
-       bScreen *screen;
-
-       Brush *brush;
-       short tool, blend;
-       Image *image;
-       ImBuf *canvas;
-       ImBuf *clonecanvas;
-       char *warnpackedfile;
-       char *warnmultifile;
-
-       /* viewport texture paint only, but _not_ project paint */
-       Object *ob;
-       int faceindex;
-       float uv[2];
-       int do_facesel;
-
-       DerivedMesh    *dm;
-       int             dm_totface;
-       int             dm_release;
-
-       MFace          *dm_mface;
-       MTFace         *dm_mtface;
-} ImagePaintState;
-
-typedef struct ImagePaintPartialRedraw {
-       int x1, y1, x2, y2;  /* XXX, could use 'rcti' */
-       int enabled;
-} ImagePaintPartialRedraw;
-
-typedef struct ImagePaintRegion {
-       int destx, desty;
-       int srcx, srcy;
-       int width, height;
-} ImagePaintRegion;
+#define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f)  {                                   \
+       (c)[0] = f_to_char((f)[0]);                                               \
+       (c)[1] = f_to_char((f)[1]);                                               \
+       (c)[2] = f_to_char((f)[2]);                                               \
+} (void)0
 
 /* ProjectionPaint defines */
 
@@ -411,8 +357,6 @@ typedef struct UndoImageTile {
        char gen_type;
 } UndoImageTile;
 
-static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
-
 /* UNDO */
 
 static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore)
@@ -433,45 +377,6 @@ static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int
                            tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
 }
 
-static void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
-{
-       ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
-       UndoImageTile *tile;
-       int allocsize;
-       short use_float = ibuf->rect_float ? 1 : 0;
-
-       for (tile = lb->first; tile; tile = tile->next)
-               if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source)
-                       if (tile->use_float == use_float)
-                               if (strcmp(tile->idname, ima->id.name) == 0 && strcmp(tile->ibufname, ibuf->name) == 0)
-                                       return tile->rect.pt;
-
-       if (*tmpibuf == NULL)
-               *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
-
-       tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
-       BLI_strncpy(tile->idname, ima->id.name, sizeof(tile->idname));
-       tile->x = x_tile;
-       tile->y = y_tile;
-
-       allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
-       allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char);
-       tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect");
-
-       BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname));
-
-       tile->gen_type = ima->gen_type;
-       tile->source = ima->source;
-       tile->use_float = use_float;
-
-       undo_copy_tile(tile, *tmpibuf, ibuf, 0);
-       undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
-
-       BLI_addtail(lb, tile);
-
-       return tile->rect.pt;
-}
-
 static void image_undo_restore(bContext *C, ListBase *lb)
 {
        Main *bmain = CTX_data_main(C);
@@ -3637,7 +3542,7 @@ static int project_image_refresh_tagged(ProjPaintState *ps)
                        for (i = 0; i < PROJ_BOUNDBOX_SQUARED; i++) {
                                pr = &(projIma->partRedrawRect[i]);
                                if (pr->x2 != -1) { /* TODO - use 'enabled' ? */
-                                       imapaintpartial = *pr;
+                                       set_imapaintpartial(pr);
                                        imapaint_image_update(NULL, projIma->ima, projIma->ibuf, true);
                                        redraw = 1;
                                }
@@ -4319,7 +4224,7 @@ static int project_paint_op(void *state, const float lastpos[2], const float pos
 }
 
 
-static int project_paint_stroke(ProjPaintState *ps, const int prevmval_i[2], const int mval_i[2], float UNUSED(pressure))
+static int project_paint_stroke(ProjPaintState *ps, const int prevmval_i[2], const int mval_i[2])
 {
        int a, redraw;
        float pos[2], prev_pos[2];
@@ -4343,428 +4248,6 @@ static int project_paint_stroke(ProjPaintState *ps, const int prevmval_i[2], con
 
 /* Imagepaint Partial Redraw & Dirty Region */
 
-static void imapaint_clear_partial_redraw(void)
-{
-       memset(&imapaintpartial, 0, sizeof(imapaintpartial));
-}
-
-static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
-{
-       ImBuf *tmpibuf = NULL;
-       int srcx = 0, srcy = 0, origx;
-
-       IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
-
-       if (w == 0 || h == 0)
-               return;
-
-       if (!imapaintpartial.enabled) {
-               imapaintpartial.x1 = x;
-               imapaintpartial.y1 = y;
-               imapaintpartial.x2 = x + w;
-               imapaintpartial.y2 = y + h;
-               imapaintpartial.enabled = 1;
-       }
-       else {
-               imapaintpartial.x1 = min_ii(imapaintpartial.x1, x);
-               imapaintpartial.y1 = min_ii(imapaintpartial.y1, y);
-               imapaintpartial.x2 = max_ii(imapaintpartial.x2, x + w);
-               imapaintpartial.y2 = max_ii(imapaintpartial.y2, y + h);
-       }
-
-       w = ((x + w - 1) >> IMAPAINT_TILE_BITS);
-       h = ((y + h - 1) >> IMAPAINT_TILE_BITS);
-       origx = (x >> IMAPAINT_TILE_BITS);
-       y = (y >> IMAPAINT_TILE_BITS);
-
-       for (; y <= h; y++)
-               for (x = origx; x <= w; x++)
-                       image_undo_push_tile(ima, ibuf, &tmpibuf, x, y);
-
-       ibuf->userflags |= IB_BITMAPDIRTY;
-
-       if (tmpibuf)
-               IMB_freeImBuf(tmpibuf);
-}
-
-static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint)
-{
-       if (imapaintpartial.x1 != imapaintpartial.x2 &&
-           imapaintpartial.y1 != imapaintpartial.y2)
-       {
-               IMB_partial_display_buffer_update_delayed(ibuf, imapaintpartial.x1, imapaintpartial.y1,
-                                                         imapaintpartial.x2, imapaintpartial.y2);
-       }
-
-       if (ibuf->mipmap[0])
-               ibuf->userflags |= IB_MIPMAP_INVALID;
-
-       /* todo: should set_tpage create ->rect? */
-       if (texpaint || (sima && sima->lock)) {
-               int w = imapaintpartial.x2 - imapaintpartial.x1;
-               int h = imapaintpartial.y2 - imapaintpartial.y1;
-               /* Testing with partial update in uv editor too */
-               GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h); //!texpaint);
-       }
-}
-
-/* Image Paint Operations */
-
-/* keep these functions in sync */
-static void imapaint_ibuf_rgb_get(ImBuf *ibuf, int x, int y, const short is_torus, float r_rgb[3])
-{
-       if (is_torus) {
-               x %= ibuf->x;
-               if (x < 0) x += ibuf->x;
-               y %= ibuf->y;
-               if (y < 0) y += ibuf->y;
-       }
-
-       if (ibuf->rect_float) {
-               float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
-               IMAPAINT_FLOAT_RGB_COPY(r_rgb, rrgbf);
-       }
-       else {
-               char *rrgb = (char *)ibuf->rect + (ibuf->x * y + x) * 4;
-               IMAPAINT_CHAR_RGB_TO_FLOAT(r_rgb, rrgb);
-       }
-}
-static void imapaint_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const short is_torus, const float rgb[3])
-{
-       if (is_torus) {
-               x %= ibuf->x;
-               if (x < 0) x += ibuf->x;
-               y %= ibuf->y;
-               if (y < 0) y += ibuf->y;
-       }
-
-       if (ibuf->rect_float) {
-               float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
-               IMAPAINT_FLOAT_RGB_COPY(rrgbf, rgb);
-       }
-       else {
-               char *rrgb = (char *)ibuf->rect + (ibuf->x * y + x) * 4;
-               IMAPAINT_FLOAT_RGB_TO_CHAR(rrgb, rgb);
-       }
-}
-
-static int imapaint_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus)
-{
-       float inrgb[3];
-
-       // XXX: signed unsigned mismatch
-       if ((x >= (unsigned int)(ibuf->x)) || (y >= (unsigned int)(ibuf->y))) {
-               if (torus) imapaint_ibuf_rgb_get(ibuf, x, y, 1, inrgb);
-               else return 0;
-       }
-       else {
-               imapaint_ibuf_rgb_get(ibuf, x, y, 0, inrgb);
-       }
-
-       outrgb[0] += inrgb[0];
-       outrgb[1] += inrgb[1];
-       outrgb[2] += inrgb[2];
-
-       return 1;
-}
-
-static void imapaint_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const short is_torus)
-{
-       int x, y, count, xi, yi, xo, yo;
-       int out_off[2], in_off[2], dim[2];
-       float outrgb[3];
-
-       dim[0] = ibufb->x;
-       dim[1] = ibufb->y;
-       in_off[0] = pos[0];
-       in_off[1] = pos[1];
-       out_off[0] = out_off[1] = 0;
-
-       if (!is_torus) {
-               IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
-                            &out_off[1], &dim[0], &dim[1]);
-
-               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;
-
-                       count = 1;
-                       imapaint_ibuf_rgb_get(ibuf, xi, yi, is_torus, outrgb);
-
-                       count += imapaint_ibuf_add_if(ibuf, xi - 1, yi - 1, outrgb, is_torus);
-                       count += imapaint_ibuf_add_if(ibuf, xi - 1, yi, outrgb, is_torus);
-                       count += imapaint_ibuf_add_if(ibuf, xi - 1, yi + 1, outrgb, is_torus);
-
-                       count += imapaint_ibuf_add_if(ibuf, xi, yi - 1, outrgb, is_torus);
-                       count += imapaint_ibuf_add_if(ibuf, xi, yi + 1, outrgb, is_torus);
-
-                       count += imapaint_ibuf_add_if(ibuf, xi + 1, yi - 1, outrgb, is_torus);
-                       count += imapaint_ibuf_add_if(ibuf, xi + 1, yi, outrgb, is_torus);
-                       count += imapaint_ibuf_add_if(ibuf, xi + 1, yi + 1, outrgb, is_torus);
-
-                       mul_v3_fl(outrgb, 1.0f / (float)count);
-
-                       /* write into brush buffer */
-                       xo = out_off[0] + x;
-                       yo = out_off[1] + y;
-                       imapaint_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb);
-               }
-       }
-}
-
-static void imapaint_set_region(ImagePaintRegion *region, int destx, int desty, int srcx, int srcy, int width, int height)
-{
-       region->destx = destx;
-       region->desty = desty;
-       region->srcx = srcx;
-       region->srcy = srcy;
-       region->width = width;
-       region->height = height;
-}
-
-static int imapaint_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf)
-{
-       int destx = region->destx;
-       int desty = region->desty;
-       int srcx = region->srcx;
-       int srcy = region->srcy;
-       int width = region->width;
-       int height = region->height;
-       int origw, origh, w, h, tot = 0;
-
-       /* convert destination and source coordinates to be within image */
-       destx = destx % dbuf->x;
-       if (destx < 0) destx += dbuf->x;
-       desty = desty % dbuf->y;
-       if (desty < 0) desty += dbuf->y;
-       srcx = srcx % sbuf->x;
-       if (srcx < 0) srcx += sbuf->x;
-       srcy = srcy % sbuf->y;
-       if (srcy < 0) srcy += sbuf->y;
-
-       /* clip width of blending area to destination imbuf, to avoid writing the
-        * same pixel twice */
-       origw = w = (width > dbuf->x) ? dbuf->x : width;
-       origh = h = (height > dbuf->y) ? dbuf->y : height;
-
-       /* clip within image */
-       IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h);
-       imapaint_set_region(&region[tot++], destx, desty, srcx, srcy, w, h);
-
-       /* do 3 other rects if needed */
-       if (w < origw)
-               imapaint_set_region(&region[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h);
-       if (h < origh)
-               imapaint_set_region(&region[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h);
-       if ((w < origw) && (h < origh))
-               imapaint_set_region(&region[tot++], (destx + w) % dbuf->x, (desty + h) % dbuf->y, (srcx + w) % sbuf->x, (srcy + h) % sbuf->y, origw - w, origh - h);
-
-       return tot;
-}
-
-static void imapaint_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos)
-{
-       ImagePaintRegion region[4];
-       int a, tot;
-
-       imapaint_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y);
-       tot = imapaint_torus_split_region(region, ibufb, ibuf);
-
-       for (a = 0; a < tot; a++)
-               IMB_rectblend(ibufb, ibuf, region[a].destx, region[a].desty,
-                             region[a].srcx, region[a].srcy,
-                             region[a].width, region[a].height, IMB_BLEND_COPY_RGB);
-}
-
-static ImBuf *imapaint_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
-{
-       /* note: allocImbuf returns zero'd memory, so regions outside image will
-        * have zero alpha, and hence not be blended onto the image */
-       int w = ibufb->x, h = ibufb->y, destx = 0, desty = 0, srcx = pos[0], srcy = pos[1];
-       ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
-
-       IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
-       IMB_rectblend(clonebuf, ibuf, destx, desty, srcx, srcy, w, h,
-                     IMB_BLEND_COPY_RGB);
-       IMB_rectblend(clonebuf, ibufb, destx, desty, destx, desty, w, h,
-                     IMB_BLEND_COPY_ALPHA);
-
-       return clonebuf;
-}
-
-static void imapaint_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[2])
-{
-       ipos[0] = (int)floorf((pos[0] - ibufb->x / 2) + 1.0f);
-       ipos[1] = (int)floorf((pos[1] - ibufb->y / 2) + 1.0f);
-}
-
-/* dosnt run for projection painting
- * only the old style painting in the 3d view */
-static int imapaint_paint_op(void *state, ImBuf *ibufb, const float lastpos[2], const float pos[2])
-{
-       ImagePaintState *s = ((ImagePaintState *)state);
-       ImBuf *clonebuf = NULL, *frombuf;
-       ImagePaintRegion region[4];
-       short torus = s->brush->flag & BRUSH_TORUS;
-       short blend = s->blend;
-       float *offset = s->brush->clone.offset;
-       float liftpos[2];
-       int bpos[2], blastpos[2], bliftpos[2];
-       int a, tot;
-
-       imapaint_convert_brushco(ibufb, pos, bpos);
-
-       /* lift from canvas */
-       if (s->tool == PAINT_TOOL_SOFTEN) {
-               imapaint_lift_soften(s->canvas, ibufb, bpos, torus);
-       }
-       else if (s->tool == PAINT_TOOL_SMEAR) {
-               if (lastpos[0] == pos[0] && lastpos[1] == pos[1])
-                       return 0;
-
-               imapaint_convert_brushco(ibufb, lastpos, blastpos);
-               imapaint_lift_smear(s->canvas, ibufb, blastpos);
-       }
-       else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
-               liftpos[0] = pos[0] - offset[0] * s->canvas->x;
-               liftpos[1] = pos[1] - offset[1] * s->canvas->y;
-
-               imapaint_convert_brushco(ibufb, liftpos, bliftpos);
-               clonebuf = imapaint_lift_clone(s->clonecanvas, ibufb, bliftpos);
-       }
-
-       frombuf = (clonebuf) ? clonebuf : ibufb;
-
-       if (torus) {
-               imapaint_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
-               tot = imapaint_torus_split_region(region, s->canvas, frombuf);
-       }
-       else {
-               imapaint_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
-               tot = 1;
-       }
-
-       /* blend into canvas */
-       for (a = 0; a < tot; a++) {
-               imapaint_dirty_region(s->image, s->canvas,
-                                     region[a].destx, region[a].desty,
-                                     region[a].width, region[a].height);
-
-               IMB_rectblend(s->canvas, frombuf,
-                             region[a].destx, region[a].desty,
-                             region[a].srcx, region[a].srcy,
-                             region[a].width, region[a].height, blend);
-       }
-
-       if (clonebuf) IMB_freeImBuf(clonebuf);
-
-       return 1;
-}
-
-
-static int imapaint_canvas_set(ImagePaintState *s, Image *ima)
-{
-       ImBuf *ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
-
-       /* verify that we can paint and set canvas */
-       if (ima == NULL) {
-               return 0;
-       }
-       else if (ima->packedfile && ima->rr) {
-               s->warnpackedfile = ima->id.name + 2;
-               return 0;
-       }
-       else if (ibuf && ibuf->channels != 4) {
-               s->warnmultifile = ima->id.name + 2;
-               return 0;
-       }
-       else if (!ibuf || !(ibuf->rect || ibuf->rect_float))
-               return 0;
-
-       s->image = ima;
-       s->canvas = ibuf;
-
-       /* set clone canvas */
-       if (s->tool == PAINT_TOOL_CLONE) {
-               ima = s->brush->clone.image;
-               ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
-
-               if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
-                       BKE_image_release_ibuf(ima, ibuf, NULL);
-                       BKE_image_release_ibuf(s->image, s->canvas, NULL);
-                       return 0;
-               }
-
-               s->clonecanvas = ibuf;
-
-               /* temporarily add float rect for cloning */
-               if (s->canvas->rect_float && !s->clonecanvas->rect_float) {
-                       IMB_float_from_rect(s->clonecanvas);
-               }
-               else if (!s->canvas->rect_float && !s->clonecanvas->rect)
-                       IMB_rect_from_float(s->clonecanvas);
-       }
-
-       return 1;
-}
-
-static void imapaint_canvas_free(ImagePaintState *s)
-{
-       BKE_image_release_ibuf(s->image, s->canvas, NULL);
-       BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL);
-}
-
-static int imapaint_paint_sub_stroke(ImagePaintState *s, BrushPainter *painter, Image *image, float *uv, int update, float pressure)
-{
-       ImBuf *ibuf = BKE_image_acquire_ibuf(image, s->sima ? &s->sima->iuser : NULL, NULL);
-       float pos[2];
-       int is_data;
-
-       if (!ibuf)
-               return 0;
-
-       is_data = ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA;
-
-       pos[0] = uv[0] * ibuf->x;
-       pos[1] = uv[1] * ibuf->y;
-
-       BKE_brush_painter_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0, 0);
-
-       /* OCIO_TODO: float buffers are now always linear, so always use color correction
-        *            this should probably be changed when texture painting color space is supported
-        */
-       if (BKE_brush_painter_paint(painter, imapaint_paint_op, pos, 0, pressure, s, is_data == FALSE)) {
-               if (update)
-                       imapaint_image_update(s->sima, image, ibuf, false);
-               BKE_image_release_ibuf(image, ibuf, NULL);
-               return 1;
-       }
-       else {
-               BKE_image_release_ibuf(image, ibuf, NULL);
-               return 0;
-       }
-}
-
-static int imapaint_paint_stroke(ImagePaintState *s, BrushPainter *painter, const int mval[2], float pressure)
-{
-       float newuv[2];
-       int redraw = 0;
-
-       UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &newuv[0], &newuv[1]);
-       redraw |= imapaint_paint_sub_stroke(s, painter, s->image, newuv,
-                                                   1, pressure);
-
-       if (redraw)
-               imapaint_clear_partial_redraw();
-
-       return redraw;
-}
 
 /************************ image paint poll ************************/
 
@@ -4811,8 +4294,7 @@ typedef enum TexPaintMode {
 typedef struct PaintOperation {
        TexPaintMode mode;
 
-       BrushPainter *painter;
-       ImagePaintState s;
+       void *custom_paint;
        ProjPaintState ps;
 
        int first;
@@ -4824,20 +4306,18 @@ typedef struct PaintOperation {
        wmTimer *timer;
 } PaintOperation;
 
-static void paint_redraw(const bContext *C, ImagePaintState *s, int final)
+static void paint_redraw(const bContext *C, PaintOperation *pop, int final)
 {
-       if (final) {
-               if (s->image && !(s->sima && s->sima->lock))
-                       GPU_free_image(s->image);
-
-               /* compositor listener deals with updating */
-               WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
-       }
-       else {
-               if (!s->sima || !s->sima->lock)
+       if (pop->mode == PAINT_MODE_2D) {
+               paint_2d_redraw(C, pop->custom_paint, final);
+       } else {
+               if (final) {
+                       /* compositor listener deals with updating */
+                       WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, NULL);
+               }
+               else {
                        ED_region_tag_redraw(CTX_wm_region(C));
-               else
-                       WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
+               }
        }
 }
 
@@ -4910,17 +4390,6 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps)
                ps->do_mask_normal = FALSE;  /* no need to do blending */
 }
 
-static void paint_brush_init_tex(Brush *brush)
-{
-       /* init mtex nodes */
-       if (brush) {
-               MTex *mtex = &brush->mtex;
-               if (mtex->tex && mtex->tex->nodetree)
-                       ntreeTexBeginExecTree(mtex->tex->nodetree, 1);  /* has internal flag to detect it only does it once */
-       }
-
-}
-
 static PaintOperation * texture_paint_init(bContext *C, wmOperator *op)
 {
        Scene *scene = CTX_data_scene(C);
@@ -4937,67 +4406,15 @@ static PaintOperation * texture_paint_init(bContext *C, wmOperator *op)
                pop->mode = PAINT_MODE_3D_PROJECT;
        }
        else {
-               pop->s.sima = CTX_wm_space_image(C);
-               pop->s.v2d = &CTX_wm_region(C)->v2d;
-       }
-
-       pop->s.scene = scene;
-       pop->s.screen = CTX_wm_screen(C);
-
-       pop->s.brush = brush;
-       pop->s.tool = brush->imagepaint_tool;
-       pop->s.blend = brush->blend;
-       pop->orig_brush_size = BKE_brush_size_get(scene, brush);
-
-       if (pop->mode != PAINT_MODE_2D) {
-               Object *ob = OBACT;
-               Mesh *me = BKE_mesh_from_object(ob);
-
-               if (!me) {
-                       return 0;
-               }
-
-               pop->s.ob = ob;
-               pop->s.do_facesel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
-
-               /* for non prohect paint we need */
-               /* fill in derived mesh */
-               if (ob->derivedFinal && CustomData_has_layer(&ob->derivedFinal->faceData, CD_MTFACE)) {
-                       pop->s.dm = ob->derivedFinal;
-                       pop->s.dm_release = FALSE;
-               }
-               else {
-                       pop->s.dm = mesh_get_derived_final(pop->s.scene, ob, pop->s.scene->customdata_mask | CD_MASK_MTFACE);
-                       pop->s.dm_release = TRUE;
-               }
-
-               if (!CustomData_has_layer(&pop->s.dm->faceData, CD_MTFACE)) {
-
-                       if (pop->s.dm_release)
-                               pop->s.dm->release(pop->s.dm);
-
-                       pop->s.dm = NULL;
+               pop->mode = PAINT_MODE_2D;
+               pop->custom_paint = paint_2d_new_stroke(C, op);
+               if (!pop->custom_paint) {
                        MEM_freeN(pop);
                        return NULL;
                }
-
-               pop->s.dm_mface = pop->s.dm->getTessFaceArray(pop->s.dm);
-               pop->s.dm_mtface = pop->s.dm->getTessFaceDataArray(pop->s.dm, CD_MTFACE);
-               pop->s.dm_totface = pop->s.dm->getNumTessFaces(pop->s.dm);
        }
-       else {
-               pop->s.image = pop->s.sima->image;
 
-               if (!imapaint_canvas_set(&pop->s, pop->s.image)) {
-                       if (pop->s.warnmultifile)
-                               BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint");
-                       if (pop->s.warnpackedfile)
-                               BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted");
-
-                       MEM_freeN(pop);
-                       return NULL;
-               }
-       }
+       pop->orig_brush_size = BKE_brush_size_get(scene, brush);
 
        /* note, if we have no UVs on the derived mesh, then we must return here */
        if (pop->mode == PAINT_MODE_3D_PROJECT) {
@@ -5029,17 +4446,11 @@ static PaintOperation * texture_paint_init(bContext *C, wmOperator *op)
                        return NULL;
                }
        }
-       else {
-               paint_brush_init_tex(pop->s.brush);
-       }
 
        settings->imapaint.flag |= IMAGEPAINT_DRAWING;
        undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
                              image_undo_restore, image_undo_free);
 
-       /* create painter */
-       pop->painter = BKE_brush_painter_new(scene, pop->s.brush);
-
        {
                UnifiedPaintSettings *ups = &settings->unified_paint_settings;
                ups->draw_pressure = true;
@@ -5053,43 +4464,35 @@ static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, Po
        PaintOperation *pop = paint_stroke_mode_data(stroke);
        float mousef[2];
        float pressure;
-       int mouse[2], redraw;
+       int mouse[2], redraw, eraser;
 
        RNA_float_get_array(itemptr, "mouse", mousef);
        mouse[0] = (int)(mousef[0]);
        mouse[1] = (int)(mousef[1]);
        pressure = RNA_float_get(itemptr, "pressure");
+       eraser = RNA_boolean_get(itemptr, "pen_flip");
 
        if (pop->mode == PAINT_MODE_3D_PROJECT) {
                if (pop->first)
                        project_paint_begin_clone(&pop->ps, mouse);
 
-               redraw = project_paint_stroke(&pop->ps, pop->prevmouse, mouse, pressure);
+               redraw = project_paint_stroke(&pop->ps, pop->prevmouse, mouse);
                pop->prevmouse[0] = mouse[0];
                pop->prevmouse[1] = mouse[1];
 
        }
        else {
-               redraw = imapaint_paint_stroke(&pop->s, pop->painter, mouse, pressure);
+               redraw = paint_2d_stroke(pop->custom_paint, mouse, pressure, eraser);
                pop->prevmouse[0] = mouse[0];
                pop->prevmouse[1] = mouse[1];
        }
 
        if (redraw)
-               paint_redraw(C, &pop->s, 0);
+               paint_redraw(C, pop, 0);
 
        pop->first = 0;
 }
 
-static void paint_brush_exit_tex(Brush *brush)
-{
-       if (brush) {
-               MTex *mtex = &brush->mtex;
-               if (mtex->tex && mtex->tex->nodetree)
-                       ntreeTexEndExecTree(mtex->tex->nodetree->execdata, 1);
-       }
-}
-
 static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
 {
        Scene *scene = CTX_data_scene(C);
@@ -5100,24 +4503,16 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
                WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), pop->timer);
 
        settings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
-       imapaint_canvas_free(&pop->s);
-       BKE_brush_painter_free(pop->painter);
 
        if (pop->mode == PAINT_MODE_3D_PROJECT) {
                BKE_brush_size_set(scene, pop->ps.brush, pop->orig_brush_size);
                paint_brush_exit_tex(pop->ps.brush);
 
                project_paint_end(&pop->ps);
-       }
-       else {
-               paint_brush_exit_tex(pop->s.brush);
-
-               /* non projection 3d paint, could move into own function of more needs adding */
-               if (pop->s.dm_release)
-                       pop->s.dm->release(pop->s.dm);
-       }
+       } else
+               paint_2d_stroke_done(pop->custom_paint);
 
-       paint_redraw(C, &pop->s, 1);
+       paint_redraw(C, pop, 1);
        undo_paint_push_end(UNDO_PAINT_IMAGE);
 
        /* duplicate warning, see texpaint_init
index 36b1e56..91ef6b8 100644 (file)
@@ -50,6 +50,8 @@ struct ViewContext;
 struct wmEvent;
 struct wmOperator;
 struct wmOperatorType;
+struct ImagePaintState;
+enum PaintMode;
 
 /* paint_stroke.c */
 typedef int (*StrokeGetLocation)(struct bContext *C, float location[3], const float mouse[2]);
@@ -64,6 +66,7 @@ void paint_stroke_data_free(struct wmOperator *op);
 
 bool paint_space_stroke_enabled(struct Brush *br);
 bool paint_supports_dynamic_size(struct Brush *br);
+bool paint_supports_jitter(enum PaintMode mode);
 
 struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf);
 int paint_stroke_modal(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
@@ -103,7 +106,30 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
 unsigned int vpaint_get_current_col(struct VPaint *vp);
 
 /* paint_image.c */
+typedef struct ImagePaintPartialRedraw {
+       int x1, y1, x2, y2;  /* XXX, could use 'rcti' */
+       int enabled;
+} ImagePaintPartialRedraw;
+
+#define IMAPAINT_TILE_BITS          6
+#define IMAPAINT_TILE_SIZE          (1 << IMAPAINT_TILE_BITS)
+#define IMAPAINT_TILE_NUMBER(size)  (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
+
+#define IMAPAINT_CHAR_TO_FLOAT(c) ((c) / 255.0f)
+
 int image_texture_paint_poll(struct bContext *C);
+void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile);
+void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, short texpaint);
+struct ImagePaintPartialRedraw *get_imapaintpartial(void);
+void set_imapaintpartial(struct ImagePaintPartialRedraw * ippr);
+void imapaint_clear_partial_redraw(void);
+void imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h);
+void *paint_2d_new_stroke(struct bContext *, struct wmOperator *);
+void paint_2d_redraw(const bContext *C, void *ps, int final);
+void paint_2d_stroke_done(void *ps);
+int paint_2d_stroke(void *ps, const int mval[2], float pressure, int eraser);
+void paint_brush_init_tex(struct Brush *brush);
+void paint_brush_exit_tex(struct Brush *brush);
 
 void PAINT_OT_image_paint(struct wmOperatorType *ot);
 void PAINT_OT_grab_clone(struct wmOperatorType *ot);
index 287bd72..2146c74 100644 (file)
@@ -157,7 +157,7 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *ev
 
        /* TODO: as sculpt and other paint modes are unified, this
         * separation will go away */
-       if (ELEM(mode, PAINT_SCULPT, PAINT_TEXTURE_PROJECTIVE)) {
+       if (paint_supports_jitter(mode)) {
                float delta[2];
 
                BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out);
@@ -338,6 +338,10 @@ bool paint_supports_dynamic_size(Brush *br)
               !ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK);
 }
 
+bool paint_supports_jitter(PaintMode mode) {
+       return ELEM(mode, PAINT_SCULPT, PAINT_TEXTURE_PROJECTIVE);
+}
+
 #define PAINT_STROKE_MODAL_CANCEL 1
 
 /* called in paint_ops.c, on each regeneration of keymaps  */