Bugfix #22040
[blender.git] / source / blender / editors / sculpt_paint / paint_image.c
index 2da638fca417426fb1b8ba1527bc62ebd342c1d0..46bcd1f1c0da2cd147b98137fc3f47600fe98b7b 100644 (file)
 #include "DNA_meshdata_types.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
+#include "DNA_brush_types.h"
 
 #include "BKE_context.h"
 #include "BKE_idprop.h"
 #include "BKE_object.h"
 #include "BKE_brush.h"
-#include "BKE_global.h"
 #include "BKE_image.h"
 #include "BKE_main.h"
 #include "BKE_mesh.h"
-#include "BKE_node.h"
 #include "BKE_paint.h"
-#include "BKE_utildefines.h"
 #include "BKE_DerivedMesh.h"
 #include "BKE_report.h"
 #include "BKE_depsgraph.h"
@@ -165,17 +163,17 @@ typedef struct ImagePaintRegion {
 #define PROJ_DEBUG_WINCLIP 1
 
 /* projectFaceSeamFlags options */
-//#define PROJ_FACE_IGNORE     1<<0    /* When the face is hidden, backfacing or occluded */
-//#define PROJ_FACE_INIT       1<<1    /* When we have initialized the faces data */
-#define PROJ_FACE_SEAM1        1<<0    /* If this face has a seam on any of its edges */
-#define PROJ_FACE_SEAM2        1<<1
-#define PROJ_FACE_SEAM3        1<<2
-#define PROJ_FACE_SEAM4        1<<3
-
-#define PROJ_FACE_NOSEAM1      1<<4
-#define PROJ_FACE_NOSEAM2      1<<5
-#define PROJ_FACE_NOSEAM3      1<<6
-#define PROJ_FACE_NOSEAM4      1<<7
+//#define PROJ_FACE_IGNORE     (1<<0)  /* When the face is hidden, backfacing or occluded */
+//#define PROJ_FACE_INIT       (1<<1)  /* When we have initialized the faces data */
+#define PROJ_FACE_SEAM1        (1<<0)  /* If this face has a seam on any of its edges */
+#define PROJ_FACE_SEAM2        (1<<1)
+#define PROJ_FACE_SEAM3        (1<<2)
+#define PROJ_FACE_SEAM4        (1<<3)
+
+#define PROJ_FACE_NOSEAM1      (1<<4)
+#define PROJ_FACE_NOSEAM2      (1<<5)
+#define PROJ_FACE_NOSEAM3      (1<<6)
+#define PROJ_FACE_NOSEAM4      (1<<7)
 
 #define PROJ_SRC_VIEW          1
 #define PROJ_SRC_IMAGE_CAM     2
@@ -191,8 +189,8 @@ typedef struct ImagePaintRegion {
 #define PROJ_FACE_SCALE_SEAM   0.99f
 
 #define PROJ_BUCKET_NULL               0
-#define PROJ_BUCKET_INIT               1<<0
-// #define PROJ_BUCKET_CLONE_INIT      1<<1
+#define PROJ_BUCKET_INIT               (1<<0)
+// #define PROJ_BUCKET_CLONE_INIT      (1<<1)
 
 /* used for testing doubles, if a point is on a line etc */
 #define PROJ_GEOM_TOLERANCE 0.00075f
@@ -385,7 +383,7 @@ static void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int
                        return tile->rect;
        
        if (*tmpibuf==NULL)
-               *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat|IB_rect, 0);
+               *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat|IB_rect);
        
        tile= MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
        strcpy(tile->idname, ima->id.name);
@@ -412,7 +410,7 @@ static void image_undo_restore(bContext *C, ListBase *lb)
        UndoImageTile *tile;
 
        tmpibuf= IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
-                                                       IB_rectfloat|IB_rect, 0);
+                                                       IB_rectfloat|IB_rect);
        
        for(tile=lb->first; tile; tile=tile->next) {
                /* find image based on name, pointer becomes invalid with global undo */
@@ -475,8 +473,6 @@ static int project_bucket_offset_safe(const ProjPaintState *ps, const float proj
        }
 }
 
-#define SIDE_OF_LINE(pa, pb, pp)       ((pa[0]-pp[0])*(pb[1]-pp[1]))-((pb[0]-pp[0])*(pa[1]-pp[1]))
-
 /* still use 2D X,Y space but this works for verts transformed by a perspective matrix, using their 4th component as a weight */
 static void barycentric_weights_v2_persp(float v1[4], float v2[4], float v3[4], float co[2], float w[3])
 {
@@ -641,8 +637,8 @@ static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float
                }
        }
        else {
-               xi = (uv[0]*ibuf->x) + 0.5f;
-               yi = (uv[1]*ibuf->y) + 0.5f;
+               xi = (int)((uv[0]*ibuf->x) + 0.5f);
+               yi = (int)((uv[1]*ibuf->y) + 0.5f);
                
                //if (xi<0 || xi>=ibuf->x  ||  yi<0 || yi>=ibuf->y) return 0;
                
@@ -1015,8 +1011,11 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const fl
        float puv[4][2]; /* pixelspace uv's */
        float no1[2], no2[2], no3[2], no4[2]; /* normals */
        float dir1[2], dir2[2], dir3[2], dir4[2];
-       float ibuf_inv[2] = {1.0f / (float)ibuf_x, 1.0f / (float)ibuf_y};
-       
+       float ibuf_inv[2];
+
+       ibuf_inv[0]= 1.0f / (float)ibuf_x;
+       ibuf_inv[1]= 1.0f / (float)ibuf_y;
+
        /* make UV's in pixel space so we can */
        puv[0][0] = orig_uv[0][0] * ibuf_x;
        puv[0][1] = orig_uv[0][1] * ibuf_y;
@@ -1053,15 +1052,15 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const fl
         * This is incorrect. Its already given radians but without it wont work.
         * need to look into a fix - campbell */
        if (is_quad) {
-               a1 = shell_angle_to_dist(angle_normalized_v2v2(dir4, dir1) * (M_PI/180.0f));
-               a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * (M_PI/180.0f));
-               a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * (M_PI/180.0f));
-               a4 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir4) * (M_PI/180.0f));
+               a1 = shell_angle_to_dist(angle_normalized_v2v2(dir4, dir1) * ((float)M_PI/180.0f));
+               a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI/180.0f));
+               a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI/180.0f));
+               a4 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir4) * ((float)M_PI/180.0f));
        }
        else {
-               a1 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir1) * (M_PI/180.0f));
-               a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * (M_PI/180.0f));
-               a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * (M_PI/180.0f));
+               a1 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir1) * ((float)M_PI/180.0f));
+               a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI/180.0f));
+               a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI/180.0f));
        }
        
        if (is_quad) {
@@ -1197,7 +1196,7 @@ static void screen_px_from_persp(
                w[2] *= wtot_inv;
        }
        else {
-               w[0] = w[1] = w[2] = 1.0/3.0; /* dummy values for zero area face */
+               w[0] = w[1] = w[2] = 1.0f/3.0f; /* dummy values for zero area face */
        }
        /* done re-weighting */
        
@@ -1334,7 +1333,7 @@ float project_paint_uvpixel_mask(
        
        // This only works when the opacity dosnt change while painting, stylus pressure messes with this
        // so dont use it.
-       // if (ps->is_airbrush==0) mask *= ps->brush->alpha;
+       // if (ps->is_airbrush==0) mask *= brush_alpha(ps->brush);
        
        return mask;
 }
@@ -1444,7 +1443,7 @@ static ProjPixel *project_paint_uvpixel_init(
                        sub_v2_v2v2(co, projPixel->projCoSS, (float *)ps->cloneOffset);
                        
                        /* no need to initialize the bucket, we're only checking buckets faces and for this
-                        * the faces are alredy initialized in project_paint_delayed_face_init(...) */
+                        * the faces are already initialized in project_paint_delayed_face_init(...) */
                        if (ibuf->rect_float) {
                                if (!project_paint_PickColor(ps, co, ((ProjPixelClone *)projPixel)->clonepx.f, NULL, 1)) {
                                        ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0; /* zero alpha - ignore */
@@ -1691,10 +1690,10 @@ static float Vec2Lenf_nosqrt_other(const float *v1, const float v2_1, const floa
 /* note, use a squared value so we can use Vec2Lenf_nosqrt
  * be sure that you have done a bounds check first or this may fail */
 /* only give bucket_bounds as an arg because we need it elsewhere */
-static int project_bucket_isect_circle(const int bucket_x, const int bucket_y, const float cent[2], const float radius_squared, rctf *bucket_bounds)
+static int project_bucket_isect_circle(const float cent[2], const float radius_squared, rctf *bucket_bounds)
 {
         
-       /* Would normally to a simple intersection test, however we know the bounds of these 2 alredy intersect 
+       /* Would normally to a simple intersection test, however we know the bounds of these 2 already intersect 
         * so we only need to test if the center is inside the vertical or horizontal bounds on either axis,
         * this is even less work then an intersection test
         * 
@@ -1854,7 +1853,7 @@ static void project_bucket_clip_face(
 {
        int inside_bucket_flag = 0;
        int inside_face_flag = 0;
-       const int flip = ((SIDE_OF_LINE(v1coSS, v2coSS, v3coSS) > 0.0f) != (SIDE_OF_LINE(uv1co, uv2co, uv3co) > 0.0f));
+       const int flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
        
        float bucket_bounds_ss[4][2];
 
@@ -2136,15 +2135,15 @@ if __name__ == '__main__':
 
        
 /* checks if pt is inside a convex 2D polyline, the polyline must be ordered rotating clockwise
- * otherwise it would have to test for mixed (SIDE_OF_LINE > 0.0f) cases */
+ * otherwise it would have to test for mixed (line_point_side_v2 > 0.0f) cases */
 int IsectPoly2Df(const float pt[2], float uv[][2], const int tot)
 {
        int i;
-       if (SIDE_OF_LINE(uv[tot-1], uv[0], pt) < 0.0f)
+       if (line_point_side_v2(uv[tot-1], uv[0], pt) < 0.0f)
                return 0;
        
        for (i=1; i<tot; i++) {
-               if (SIDE_OF_LINE(uv[i-1], uv[i], pt) < 0.0f)
+               if (line_point_side_v2(uv[i-1], uv[i], pt) < 0.0f)
                        return 0;
                
        }
@@ -2154,10 +2153,10 @@ int IsectPoly2Df(const float pt[2], float uv[][2], const int tot)
 static int IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot)
 {
        int i;
-       int side = (SIDE_OF_LINE(uv[tot-1], uv[0], pt) > 0.0f);
+       int side = (line_point_side_v2(uv[tot-1], uv[0], pt) > 0.0f);
        
        for (i=1; i<tot; i++) {
-               if ((SIDE_OF_LINE(uv[i-1], uv[i], pt) > 0.0f) != side)
+               if ((line_point_side_v2(uv[i-1], uv[i], pt) > 0.0f) != side)
                        return 0;
                
        }
@@ -2513,11 +2512,11 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
                                                                                                w[0]=w[1]=w[2]= 0.0;
                                                                                                if (side) {
                                                                                                        w[fidx1?fidx1-1:0] = fac;
-                                                                                                       w[fidx2?fidx2-1:0] = 1.0-fac;
+                                                                                                       w[fidx2?fidx2-1:0] = 1.0f-fac;
                                                                                                }
                                                                                                else {
                                                                                                        w[fidx1] = fac;
-                                                                                                       w[fidx2] = 1.0-fac;
+                                                                                                       w[fidx2] = 1.0f-fac;
                                                                                                }
 #endif
                                                                                        }
@@ -2571,11 +2570,12 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
 static void project_paint_bucket_bounds(const ProjPaintState *ps, const float min[2], const float max[2], int bucketMin[2], int bucketMax[2])
 {
        /* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */
-       bucketMin[0] = (int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f; /* these offsets of 0.5 and 1.5 seem odd but they are correct */
-       bucketMin[1] = (int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 0.5f;
+       /* XXX: the offset of 0.5 is always truncated to zero and the offset of 1.5f is always truncated to 1, is this really correct?? - jwilkins */
+       bucketMin[0] = (int)((int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f); /* these offsets of 0.5 and 1.5 seem odd but they are correct */
+       bucketMin[1] = (int)((int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 0.5f);
        
-       bucketMax[0] = (int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f;
-       bucketMax[1] = (int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 1.5f;  
+       bucketMax[0] = (int)((int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f);
+       bucketMax[1] = (int)((int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 1.5f);
        
        /* incase the rect is outside the mesh 2d bounds */
        CLAMP(bucketMin[0], 0, ps->buckets_x);
@@ -2653,7 +2653,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
  * calculated when it might not be needed later, (at the moment at least)
  * obviously it shouldn't have bugs though */
 
-static int project_bucket_face_isect(ProjPaintState *ps, float min[2], float max[2], int bucket_x, int bucket_y, int bucket_index, const MFace *mf)
+static int project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int bucket_y, const MFace *mf)
 {
        /* TODO - replace this with a tricker method that uses sideofline for all screenCoords's edges against the closest bucket corner */
        rctf bucket_bounds;
@@ -2713,11 +2713,11 @@ static int project_bucket_face_isect(ProjPaintState *ps, float min[2], float max
 
 /* Add faces to the bucket but dont initialize its pixels
  * TODO - when painting occluded, sort the faces on their min-Z and only add faces that faces that are not occluded */
-static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf, const MTFace *tf, const int face_index)
+static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf, const int face_index)
 {
        float min[2], max[2], *vCoSS;
        int bucketMin[2], bucketMax[2]; /* for  ps->bucketRect indexing */
-       int fidx, bucket_x, bucket_y, bucket_index;
+       int fidx, bucket_x, bucket_y;
        int has_x_isect = -1, has_isect = 0; /* for early loop exit */
        MemArena *arena = ps->arena_mt[0]; /* just use the first thread arena since threading has not started yet */
        
@@ -2734,10 +2734,8 @@ static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf,
        for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) {
                has_x_isect = 0;
                for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x++) {
-                       
-                       bucket_index = bucket_x + (bucket_y * ps->buckets_x);
-                       
-                       if (project_bucket_face_isect(ps, min, max, bucket_x, bucket_y, bucket_index, mf)) {
+                       if (project_bucket_face_isect(ps, bucket_x, bucket_y, mf)) {
+                               int bucket_index= bucket_x + (bucket_y * ps->buckets_x);
                                BLI_linklist_prepend_arena(
                                        &ps->bucketFaces[ bucket_index ],
                                        SET_INT_IN_POINTER(face_index), /* cast to a pointer to shut up the compiler */
@@ -2808,6 +2806,8 @@ static void project_paint_begin(ProjPaintState *ps)
        MVert *mv;
        
        MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */
+
+       const int diameter= 2*brush_size(ps->brush);
        
        /* ---- end defines ---- */
        
@@ -3029,27 +3029,27 @@ static void project_paint_begin(ProjPaintState *ps)
        
        if(ps->source==PROJ_SRC_VIEW) {
 #ifdef PROJ_DEBUG_WINCLIP
-               CLAMP(ps->screenMin[0], -ps->brush->size, ps->winx + ps->brush->size);
-               CLAMP(ps->screenMax[0], -ps->brush->size, ps->winx + ps->brush->size);
+               CLAMP(ps->screenMin[0], (float)(-diameter), (float)(ps->winx + diameter));
+               CLAMP(ps->screenMax[0], (float)(-diameter), (float)(ps->winx + diameter));
 
-               CLAMP(ps->screenMin[1], -ps->brush->size, ps->winy + ps->brush->size);
-               CLAMP(ps->screenMax[1], -ps->brush->size, ps->winy + ps->brush->size);
+               CLAMP(ps->screenMin[1], (float)(-diameter), (float)(ps->winy + diameter));
+               CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + diameter));
 #endif
        }
        else { /* reprojection, use bounds */
                ps->screenMin[0]= 0;
-               ps->screenMax[0]= ps->winx;
+               ps->screenMax[0]= (float)(ps->winx);
 
                ps->screenMin[1]= 0;
-               ps->screenMax[1]= ps->winy;
+               ps->screenMax[1]= (float)(ps->winy);
        }
 
        /* only for convenience */
        ps->screen_width  = ps->screenMax[0] - ps->screenMin[0];
        ps->screen_height = ps->screenMax[1] - ps->screenMin[1];
        
-       ps->buckets_x = (int)(ps->screen_width / (((float)ps->brush->size) / PROJ_BUCKET_BRUSH_DIV));
-       ps->buckets_y = (int)(ps->screen_height / (((float)ps->brush->size) / PROJ_BUCKET_BRUSH_DIV));
+       ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
+       ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
        
        /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */
        
@@ -3193,7 +3193,7 @@ static void project_paint_begin(ProjPaintState *ps)
                                        }
                                }
                                else {
-                                       if (SIDE_OF_LINE(v1coSS, v2coSS, v3coSS) < 0.0f) {
+                                       if (line_point_side_v2(v1coSS, v2coSS, v3coSS) < 0.0f) {
                                                continue;
                                        }
                                        
@@ -3216,7 +3216,7 @@ static void project_paint_begin(ProjPaintState *ps)
                        if (image_index != -1) {
                                /* Initialize the faces screen pixels */
                                /* Add this to a list to initialize later */
-                               project_paint_delayed_face_init(ps, mf, tf, face_index);
+                               project_paint_delayed_face_init(ps, mf, face_index);
                        }
                }
        }
@@ -3447,16 +3447,16 @@ static int project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2])
 {
        if(ps->source==PROJ_SRC_VIEW) {
                float min_brush[2], max_brush[2];
-               float size_half = ((float)ps->brush->size) * 0.5f;
+               const float radius = (float)brush_size(ps->brush);
 
                /* so we dont have a bucket bounds that is way too small to paint into */
-               // if (size_half < 1.0f) size_half = 1.0f; // this dosnt work yet :/
+               // if (radius < 1.0f) radius = 1.0f; // this doesn't work yet :/
 
-               min_brush[0] = mval_f[0] - size_half;
-               min_brush[1] = mval_f[1] - size_half;
+               min_brush[0] = mval_f[0] - radius;
+               min_brush[1] = mval_f[1] - radius;
 
-               max_brush[0] = mval_f[0] + size_half;
-               max_brush[1] = mval_f[1] + size_half;
+               max_brush[0] = mval_f[0] + radius;
+               max_brush[1] = mval_f[1] + radius;
 
                /* offset to make this a valid bucket index */
                project_paint_bucket_bounds(ps, min_brush, max_brush, ps->bucketMin, ps->bucketMax);
@@ -3485,6 +3485,8 @@ static int project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2])
 
 static int project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf *bucket_bounds, const float mval[2])
 {
+       const int diameter= 2*brush_size(ps->brush);
+
        if (ps->thread_tot > 1)
                BLI_lock_thread(LOCK_CUSTOM1);
        
@@ -3497,7 +3499,7 @@ static int project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf
                        project_bucket_bounds(ps, ps->context_bucket_x, ps->context_bucket_y, bucket_bounds);
                        
                        if (    (ps->source != PROJ_SRC_VIEW) ||
-                                       project_bucket_isect_circle(ps->context_bucket_x, ps->context_bucket_y, mval, ps->brush->size * ps->brush->size, bucket_bounds)
+                                       project_bucket_isect_circle(mval, (float)(diameter*diameter), bucket_bounds)
                        ) {
                                *bucket_index = ps->context_bucket_x + (ps->context_bucket_y * ps->buckets_x);
                                ps->context_bucket_x++;
@@ -3545,26 +3547,28 @@ static void blend_color_mix(unsigned char *cp, const unsigned char *cp1, const u
 
 static void blend_color_mix_float(float *cp, const float *cp1, const float *cp2, const float fac)
 {
-       const float mfac= 1.0-fac;
+       const float mfac= 1.0f-fac;
        cp[0]= mfac*cp1[0] + fac*cp2[0];
        cp[1]= mfac*cp1[1] + fac*cp2[1];
        cp[2]= mfac*cp1[2] + fac*cp2[2];
        cp[3]= mfac*cp1[3] + fac*cp2[3];
 }
 
-static void blend_color_mix_rgb(unsigned char *cp, const unsigned char *cp1, const unsigned char *cp2, const int fac)
+static void blend_color_mix_accum(unsigned char *cp, const unsigned char *cp1, const unsigned char *cp2, const int fac)
 {
        /* this and other blending modes previously used >>8 instead of /255. both
           are not equivalent (>>8 is /256), and the former results in rounding
           errors that can turn colors black fast after repeated blending */
        const int mfac= 255-fac;
+       const int alpha= cp1[3] + ((fac * cp2[3]) / 255);
 
        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;
+       cp[3]= alpha > 255 ? 255 : alpha;
 }
 
-static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask)
+static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask)
 {
        if (ps->is_airbrush==0 && mask < 1.0f) {
                projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, ((ProjPixelClone*)projPixel)->clonepx.uint, (int)(alpha*255), ps->blend);
@@ -3575,7 +3579,7 @@ static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, floa
        }
 }
 
-static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask)
+static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask)
 {
        if (ps->is_airbrush==0 && mask < 1.0f) {
                IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, ((ProjPixelClone *)projPixel)->clonepx.f, alpha, ps->blend);
@@ -3592,7 +3596,7 @@ static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, fl
  * accumulation of color greater then 'projPixel->mask' however in the case of smear its not 
  * really that important to be correct as it is with clone and painting 
  */
-static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels, float co[2])
+static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels, float co[2])
 {
        unsigned char rgba_ub[4];
        
@@ -3603,7 +3607,7 @@ static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, floa
        BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena);
 } 
 
-static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels_f, float co[2])
+static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels_f, float co[2])
 {
        unsigned char rgba_ub[4];
        unsigned char rgba_smear[4];
@@ -3682,7 +3686,6 @@ static void *do_projectpaint_thread(void *ph_v)
        
        float rgba[4], alpha, dist_nosqrt, dist;
        
-       float brush_size_sqared;
        float falloff;
        int bucket_index;
        int is_floatbuf = 0;
@@ -3694,14 +3697,15 @@ static void *do_projectpaint_thread(void *ph_v)
        float co[2];
        float mask = 1.0f; /* airbrush wont use mask */
        unsigned short mask_short;
-       float size_half = ((float)ps->brush->size) * 0.5f;
+       const float radius= (float)brush_size(ps->brush);
+       const float radius_squared= radius*radius; /* avoid a square root with every dist comparison */
+       
        short lock_alpha= ELEM(ps->brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ? 0 : ps->brush->flag & BRUSH_LOCK_ALPHA;
        
        LinkNode *smearPixels = NULL;
        LinkNode *smearPixels_f = NULL;
        MemArena *smearArena = NULL; /* mem arena for this brush projection only */
        
-       
        if (tool==PAINT_TOOL_SMEAR) {
                pos_ofs[0] = pos[0] - lastpos[0];
                pos_ofs[1] = pos[1] - lastpos[1];
@@ -3709,9 +3713,6 @@ static void *do_projectpaint_thread(void *ph_v)
                smearArena = BLI_memarena_new(1<<16, "paint smear arena");
        }
        
-       /* avoid a square root with every dist comparison */
-       brush_size_sqared = ps->brush->size * ps->brush->size; 
-       
        /* printf("brush bounds %d %d %d %d\n", bucketMin[0], bucketMin[1], bucketMax[0], bucketMax[1]); */
        
        while (project_bucket_iter_next(ps, &bucket_index, &bucket_bounds, pos)) {                              
@@ -3732,7 +3733,8 @@ static void *do_projectpaint_thread(void *ph_v)
                                bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL, projPixel->projCoSS[0], projPixel->projCoSS[1]);
                                if(projPixel->newColor.ch[3]) {
                                        mask = ((float)projPixel->mask)/65535.0f;
-                                       blend_color_mix_rgb(projPixel->pixel.ch_pt,  projPixel->origColor.ch, projPixel->newColor.ch, (mask*projPixel->newColor.ch[3]));
+                                       blend_color_mix_accum(projPixel->pixel.ch_pt,  projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask*projPixel->newColor.ch[3]));
+
                                }
                        }
                }
@@ -3746,13 +3748,16 @@ static void *do_projectpaint_thread(void *ph_v)
                                /*dist = len_v2v2(projPixel->projCoSS, pos);*/ /* correct but uses a sqrtf */
                                dist_nosqrt = Vec2Lenf_nosqrt(projPixel->projCoSS, pos);
 
-                               /*if (dist < s->brush->size) {*/ /* correct but uses a sqrtf */
-                               if (dist_nosqrt < brush_size_sqared && (dist=sqrtf(dist_nosqrt)) < size_half) {
-                                       falloff = brush_curve_strength_clamp(ps->brush, dist, size_half);
+                               /*if (dist < radius) {*/ /* correct but uses a sqrtf */
+                               if (dist_nosqrt <= radius_squared) {
+                                       dist=sqrtf(dist_nosqrt);
+
+                                       falloff = brush_curve_strength_clamp(ps->brush, dist, radius);
 
                                        if (falloff > 0.0f) {
                                                if (ps->is_texbrush) {
-                                                       brush_sample_tex(ps->brush, projPixel->projCoSS, rgba);
+                                                       /* note, for clone and smear, we only use the alpha, could be a special function */
+                                                       brush_sample_tex(ps->brush, projPixel->projCoSS, rgba, thread_index);
                                                        alpha = rgba[3];
                                                } else {
                                                        alpha = 1.0f;
@@ -3760,7 +3765,7 @@ static void *do_projectpaint_thread(void *ph_v)
                                                
                                                if (ps->is_airbrush) {
                                                        /* for an aurbrush there is no real mask, so just multiply the alpha by it */
-                                                       alpha *= falloff * ps->brush->alpha;
+                                                       alpha *= falloff * brush_alpha(ps->brush);
                                                        mask = ((float)projPixel->mask)/65535.0f;
                                                }
                                                else {
@@ -3768,7 +3773,7 @@ static void *do_projectpaint_thread(void *ph_v)
                                                        falloff = 1.0f - falloff;
                                                        falloff = 1.0f - (falloff * falloff);
                                                        
-                                                       mask_short = projPixel->mask * (ps->brush->alpha * falloff);
+                                                       mask_short = (unsigned short)(projPixel->mask * (brush_alpha(ps->brush) * falloff));
                                                        if (mask_short > projPixel->mask_max) {
                                                                mask = ((float)mask_short)/65535.0f;
                                                                projPixel->mask_max = mask_short;
@@ -3803,20 +3808,20 @@ static void *do_projectpaint_thread(void *ph_v)
                                                        case PAINT_TOOL_CLONE:
                                                                if (is_floatbuf) {
                                                                        if (((ProjPixelClone *)projPixel)->clonepx.f[3]) {
-                                                                               do_projectpaint_clone_f(ps, projPixel, rgba, alpha, mask);
+                                                                               do_projectpaint_clone_f(ps, projPixel, alpha, mask); /* rgba isnt used for cloning, only alpha */
                                                                        }
                                                                }
                                                                else {
                                                                        if (((ProjPixelClone*)projPixel)->clonepx.ch[3]) {
-                                                                               do_projectpaint_clone(ps, projPixel, rgba, alpha, mask);
+                                                                               do_projectpaint_clone(ps, projPixel, alpha, mask); /* rgba isnt used for cloning, only alpha */
                                                                        }
                                                                }
                                                                break;
                                                        case PAINT_TOOL_SMEAR:
                                                                sub_v2_v2v2(co, projPixel->projCoSS, pos_ofs);
 
-                                                               if (is_floatbuf)        do_projectpaint_smear_f(ps, projPixel, rgba, alpha, mask, smearArena, &smearPixels_f, co);
-                                                               else                            do_projectpaint_smear(ps, projPixel, rgba, alpha, mask, smearArena, &smearPixels, co);
+                                                               if (is_floatbuf)        do_projectpaint_smear_f(ps, projPixel, alpha, mask, smearArena, &smearPixels_f, co);
+                                                               else                            do_projectpaint_smear(ps, projPixel, alpha, mask, smearArena, &smearPixels, co);
                                                                break;
                                                        default:
                                                                if (is_floatbuf)        do_projectpaint_draw_f(ps, projPixel, rgba, alpha, mask);
@@ -3856,7 +3861,7 @@ static void *do_projectpaint_thread(void *ph_v)
        return NULL;
 }
 
-static int project_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *pos)
+static int project_paint_op(void *state, ImBuf *UNUSED(ibufb), float *lastpos, float *pos)
 {
        /* First unpack args from the struct */
        ProjPaintState *ps = (ProjPaintState *)state;
@@ -3923,14 +3928,14 @@ static int project_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *po
 }
 
 
-static int project_paint_sub_stroke(ProjPaintState *ps, BrushPainter *painter, int *prevmval_i, int *mval_i, double time, float pressure)
+static int project_paint_sub_stroke(ProjPaintState *ps, BrushPainter *painter, int *UNUSED(prevmval_i), int *mval_i, double time, float pressure)
 {
        
        /* Use mouse coords as floats for projection painting */
        float pos[2];
        
-       pos[0] = mval_i[0];
-       pos[1] = mval_i[1];
+       pos[0] = (float)(mval_i[0]);
+       pos[1] = (float)(mval_i[1]);
        
        // we may want to use this later 
        // brush_painter_require_imbuf(painter, ((ibuf->rect_float)? 1: 0), 0, 0);
@@ -3959,7 +3964,7 @@ static int project_paint_stroke(ProjPaintState *ps, BrushPainter *painter, int *
 
 /* Imagepaint Partial Redraw & Dirty Region */
 
-static void imapaint_clear_partial_redraw()
+static void imapaint_clear_partial_redraw(void)
 {
        memset(&imapaintpartial, 0, sizeof(imapaintpartial));
 }
@@ -4008,8 +4013,9 @@ static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, s
        if(ibuf->rect_float)
                /* TODO - should just update a portion from imapaintpartial! */
                imb_freerectImBuf(ibuf); /* force recreate of char rect */
+       
        if(ibuf->mipmap[0])
-               imb_freemipmapImBuf(ibuf);
+               ibuf->userflags |= IB_MIPMAP_INVALID;
 
        /* todo: should set_tpage create ->rect? */
        if(texpaint || (sima && sima->lock)) {
@@ -4054,7 +4060,8 @@ static int imapaint_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, flo
 {
        float inrgb[3];
 
-       if ((x >= ibuf->x) || (y >= ibuf->y)) {
+       // XXX: signed unsigned mismatch
+       if ((x >= (unsigned int)(ibuf->x)) || (y >= (unsigned int)(ibuf->y))) {
                if (torus) imapaint_ibuf_get_set_rgb(ibuf, x, y, 1, 0, inrgb);
                else return 0;
        }
@@ -4175,7 +4182,7 @@ static void imapaint_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos)
        int a, tot;
 
        imapaint_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y);
-       tot= imapaint_torus_split_region(region, ibuf, ibufb);
+       tot= imapaint_torus_split_region(region, ibufb, ibuf);
 
        for(a=0; a<tot; a++)
                IMB_rectblend(ibufb, ibuf, region[a].destx, region[a].desty,
@@ -4188,7 +4195,7 @@ 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->depth, ibufb->flags, 0);
+       ImBuf *clonebuf= IMB_allocImBuf(w, h, ibufb->depth, ibufb->flags);
 
        IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
        IMB_rectblend(clonebuf, ibuf, destx, desty, srcx, srcy, w, h,
@@ -4381,7 +4388,7 @@ static int imapaint_paint_stroke(ViewContext *vc, ImagePaintState *s, BrushPaint
                        ibuf= BKE_image_get_ibuf(newimage, s->sima? &s->sima->iuser: NULL);
 
                        if(ibuf && ibuf->rect)
-                               imapaint_pick_uv(s->scene, s->ob, s->me, newfaceindex, mval, newuv);
+                               imapaint_pick_uv(s->scene, s->ob, newfaceindex, mval, newuv);
                        else {
                                newimage = NULL;
                                newuv[0] = newuv[1] = 0.0f;
@@ -4392,8 +4399,8 @@ static int imapaint_paint_stroke(ViewContext *vc, ImagePaintState *s, BrushPaint
 
                /* see if stroke is broken, and if so finish painting in old position */
                if (s->image) {
-                       imapaint_pick_uv(s->scene, s->ob, s->me, s->faceindex, mval, fwuv);
-                       imapaint_pick_uv(s->scene, s->ob, s->me, newfaceindex, prevmval, bkuv);
+                       imapaint_pick_uv(s->scene, s->ob, s->faceindex, mval, fwuv);
+                       imapaint_pick_uv(s->scene, s->ob, newfaceindex, prevmval, bkuv);
 
                        if (newimage == s->image)
                                breakstroke= texpaint_break_stroke(s->uv, fwuv, bkuv, newuv);
@@ -4404,7 +4411,7 @@ static int imapaint_paint_stroke(ViewContext *vc, ImagePaintState *s, BrushPaint
                        fwuv[0]= fwuv[1]= 0.0f;
 
                if (breakstroke) {
-                       imapaint_pick_uv(s->scene, s->ob, s->me, s->faceindex, mval, fwuv);
+                       imapaint_pick_uv(s->scene, s->ob, s->faceindex, mval, fwuv);
                        redraw |= imapaint_paint_sub_stroke(s, painter, s->image, texpaint,
                                fwuv, time, 1, pressure);
                        imapaint_clear_partial_redraw();
@@ -4515,11 +4522,13 @@ typedef struct PaintOperation {
        int first;
        int prevmouse[2];
        float prev_pressure; /* need this since we dont get tablet events for pressure change */
-       int brush_size_orig;
+       int orig_brush_size;
        double starttime;
 
        ViewContext vc;
        wmTimer *timer;
+
+       short restore_projection;
 } PaintOperation;
 
 static void paint_redraw(bContext *C, ImagePaintState *s, int final)
@@ -4528,29 +4537,8 @@ static void paint_redraw(bContext *C, ImagePaintState *s, int final)
                if(s->image)
                        GPU_free_image(s->image);
 
+               /* compositor listener deals with updating */
                WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, s->image);
-
-               // XXX node update
-#if 0
-               if(!s->sima && s->image) {
-                       /* after paint, tag Image or RenderResult nodes changed */
-                       if(s->scene->nodetree) {
-                               imagepaint_composite_tags(s->scene->nodetree, image, &s->sima->iuser);
-                       }
-                       /* signal composite (hurmf, need an allqueue?) */
-                       if(s->sima->lock) {
-                               ScrArea *sa;
-                               for(sa=s->screen->areabase.first; sa; sa= sa->next) {
-                                       if(sa->spacetype==SPACE_NODE) {
-                                               if(((SpaceNode *)sa->spacedata.first)->treetype==NTREE_COMPOSIT) {
-                                                       addqueue(sa->win, UI_BUT_EVENT, B_NODE_TREE_EXEC);
-                                                       break;
-                                               }
-                                       }
-                               }
-                       }
-               }               
-#endif
        }
        else {
                if(!s->sima || !s->sima->lock)
@@ -4608,8 +4596,8 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps)
                ps->normal_angle_inner= ps->normal_angle= settings->imapaint.normal_angle;
        }
 
-       ps->normal_angle_inner *=       M_PI_2 / 90;
-       ps->normal_angle *=                     M_PI_2 / 90;
+       ps->normal_angle_inner *=       (float)(M_PI_2 / 90);
+       ps->normal_angle *=                     (float)(M_PI_2 / 90);
        ps->normal_angle_range = ps->normal_angle - ps->normal_angle_inner;
 
        if(ps->normal_angle_range <= 0.0f)
@@ -4626,6 +4614,13 @@ static int texture_paint_init(bContext *C, wmOperator *op)
        pop->first= 1;
        op->customdata= pop;
        
+       /* XXX: Soften tool does not support projection painting atm, so just disable
+               projection for this brush */
+       if(brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
+               settings->imapaint.flag |= IMAGEPAINT_PROJECT_DISABLE;
+               pop->restore_projection = 1;
+       }
+
        /* initialize from context */
        if(CTX_wm_region_view3d(C)) {
                pop->mode= PAINT_MODE_3D;
@@ -4648,7 +4643,7 @@ static int texture_paint_init(bContext *C, wmOperator *op)
        if(pop->mode == PAINT_MODE_3D && (pop->s.tool == PAINT_TOOL_CLONE))
                pop->s.tool = PAINT_TOOL_DRAW;
        pop->s.blend = brush->blend;
-       pop->brush_size_orig= brush->size;
+       pop->orig_brush_size= brush_size(brush);
 
        if(pop->mode != PAINT_MODE_2D) {
                pop->s.ob = OBACT;
@@ -4680,8 +4675,8 @@ static int texture_paint_init(bContext *C, wmOperator *op)
                        return 0;
 
                /* Dont allow brush size below 2 */
-               if (brush->size <= 1)
-                       brush->size = 2;
+               if (brush_size(brush) < 2)
+                       brush_set_size(brush, 2);
 
                /* allocate and initialize spacial data structures */
                project_paint_begin(&pop->ps);
@@ -4691,7 +4686,7 @@ static int texture_paint_init(bContext *C, wmOperator *op)
        }
        
        settings->imapaint.flag |= IMAGEPAINT_DRAWING;
-       undo_paint_push_begin(UNDO_PAINT_IMAGE, "Image Paint",
+       undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
                image_undo_restore, image_undo_free);
 
        /* create painter */
@@ -4708,8 +4703,8 @@ static void paint_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
        int mouse[2], redraw;
 
        RNA_float_get_array(itemptr, "mouse", mousef);
-       mouse[0] = mousef[0];
-       mouse[1] = mousef[1];
+       mouse[0] = (int)(mousef[0]);
+       mouse[1] = (int)(mousef[1]);
        time= RNA_float_get(itemptr, "time");
        pressure= RNA_float_get(itemptr, "pressure");
 
@@ -4746,12 +4741,15 @@ static void paint_exit(bContext *C, wmOperator *op)
        if(pop->timer)
                WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), pop->timer);
 
+       if(pop->restore_projection)
+               settings->imapaint.flag &= ~IMAGEPAINT_PROJECT_DISABLE;
+
        settings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
        imapaint_canvas_free(&pop->s);
        brush_painter_free(pop->painter);
 
        if(pop->mode == PAINT_MODE_3D_PROJECT) {
-               pop->ps.brush->size = pop->brush_size_orig;
+               brush_set_size(pop->ps.brush, pop->orig_brush_size);
                project_paint_end(&pop->ps);
        }
        
@@ -4822,15 +4820,22 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event)
 
                /* special exception here for too high pressure values on first touch in
                   windows for some tablets, then we just skip first touch ..  */
-               if ((pop->s.brush->flag & (BRUSH_ALPHA_PRESSURE|BRUSH_SIZE_PRESSURE|BRUSH_SPACING_PRESSURE)) && tablet && (pressure >= 0.99f))
+               if (tablet && (pressure >= 0.99f) && ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) || brush_use_alpha_pressure(pop->s.brush) || brush_use_size_pressure(pop->s.brush)))
+                       return;
+
+               /* This can be removed once fixed properly in
+                brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, float pressure, void *user) 
+                at zero pressure we should do nothing 1/2^12 is .0002 which is the sensitivity of the most sensitive pen tablet available*/
+               if (tablet && (pressure < .0002f) && ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) || brush_use_alpha_pressure(pop->s.brush) || brush_use_size_pressure(pop->s.brush)))
                        return;
+       
        }
 
        /* fill in stroke */
        RNA_collection_add(op->ptr, "stroke", &itemptr);
 
-       mousef[0] = mouse[0];
-       mousef[1] = mouse[1];
+       mousef[0] = (float)(mouse[0]);
+       mousef[1] = (float)(mouse[1]);
        RNA_float_set_array(&itemptr, "mouse", mousef);
        RNA_float_set(&itemptr, "time", (float)(time - pop->starttime));
        RNA_float_set(&itemptr, "pressure", pressure);
@@ -4872,6 +4877,7 @@ static int paint_modal(bContext *C, wmOperator *op, wmEvent *event)
                        paint_exit(C, op);
                        return OPERATOR_FINISHED;
                case MOUSEMOVE:
+               case INBETWEEN_MOUSEMOVE:
                        paint_apply_event(C, op, event);
                        break;
                case TIMER:
@@ -4930,12 +4936,17 @@ static int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
 
 /************************ cursor drawing *******************************/
 
-static void brush_drawcursor(bContext *C, int x, int y, void *customdata)
+static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata))
 {
        Brush *brush= image_paint_brush(C);
+       Paint *paint= paint_get_active(CTX_data_scene(C));
 
-       if(brush) {
+       if(paint && brush) {
                float zoomx, zoomy;
+
+               if(!(paint->flags & PAINT_SHOW_BRUSH))
+                       return;
+
                glPushMatrix();
 
                glTranslatef((float)x, (float)y, 0.0f);
@@ -4943,13 +4954,13 @@ static void brush_drawcursor(bContext *C, int x, int y, void *customdata)
                if(get_imapaint_zoom(C, &zoomx, &zoomy))
                        glScalef(zoomx, zoomy, 1.0f);
 
-               glColor4ub(255, 255, 255, 128);
+               glColor4f(brush->add_col[0], brush->add_col[1], brush->add_col[2], 0.5f);
                glEnable( GL_LINE_SMOOTH );
                glEnable(GL_BLEND);
-               glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size*0.5f, 40);
+               glutil_draw_lined_arc(0, (float)(M_PI*2.0), (float)brush_size(brush), 40);
                glDisable(GL_BLEND);
                glDisable( GL_LINE_SMOOTH );
-               
+
                glPopMatrix();
        }
 }
@@ -4966,23 +4977,38 @@ static void toggle_paint_cursor(bContext *C, int enable)
                settings->imapaint.paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), image_paint_poll, brush_drawcursor, NULL);
 }
 
+/* enable the paint cursor if it isn't already.
+
+   purpose is to make sure the paint cursor is shown if paint
+   mode is enabled in the image editor. the paint poll will
+   ensure that the cursor is hidden when not in paint mode */
+void ED_space_image_paint_update(wmWindowManager *wm, ToolSettings *settings)
+{
+       ImagePaintSettings *imapaint = &settings->imapaint;
+
+       if(!imapaint->paintcursor) {
+               imapaint->paintcursor =
+                       WM_paint_cursor_activate(wm, image_paint_poll,
+                                                brush_drawcursor, NULL);
+       }
+}
+
 /* ************ image paint radial control *************/
 static int paint_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        float zoom;
        ToolSettings *ts = CTX_data_scene(C)->toolsettings;
        get_imapaint_zoom(C, &zoom, &zoom);
-       toggle_paint_cursor(C, !ts->imapaint.paintcursor);
-       brush_radial_control_invoke(op, paint_brush(&ts->imapaint.paint), 0.5 * zoom);
+       toggle_paint_cursor(C, 0);
+       brush_radial_control_invoke(op, paint_brush(&ts->imapaint.paint), zoom);
        return WM_radial_control_invoke(C, op, event);
 }
 
 static int paint_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
 {
-       ToolSettings *ts = CTX_data_scene(C)->toolsettings;
        int ret = WM_radial_control_modal(C, op, event);
        if(ret != OPERATOR_RUNNING_MODAL)
-                       toggle_paint_cursor(C, !ts->imapaint.paintcursor);
+               toggle_paint_cursor(C, 1);
        return ret;
 }
 
@@ -4991,10 +5017,10 @@ static int paint_radial_control_exec(bContext *C, wmOperator *op)
        Brush *brush = paint_brush(&CTX_data_scene(C)->toolsettings->imapaint.paint);
        float zoom;
        int ret;
-       char str[256];
+       char str[64];
        get_imapaint_zoom(C, &zoom, &zoom);
-       ret = brush_radial_control_exec(op, brush, 2.0 / zoom);
-       WM_radial_control_string(op, str, 256);
+       ret = brush_radial_control_exec(op, brush, 1.0f / zoom);
+       WM_radial_control_string(op, str, sizeof(str));
        
        WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush);
 
@@ -5089,7 +5115,7 @@ static int grab_clone_modal(bContext *C, wmOperator *op, wmEvent *event)
        return OPERATOR_RUNNING_MODAL;
 }
 
-static int grab_clone_cancel(bContext *C, wmOperator *op)
+static int grab_clone_cancel(bContext *UNUSED(C), wmOperator *op)
 {
        MEM_freeN(op->customdata);
        return OPERATOR_CANCELLED;
@@ -5137,11 +5163,40 @@ static int sample_color_invoke(bContext *C, wmOperator *op, wmEvent *event)
        ARegion *ar= CTX_wm_region(C);
        int location[2];
 
-       location[0]= event->x - ar->winrct.xmin;
-       location[1]= event->y - ar->winrct.ymin;
-       RNA_int_set_array(op->ptr, "location", location);
+       if(ar) {
+               location[0]= event->x - ar->winrct.xmin;
+               location[1]= event->y - ar->winrct.ymin;
+               RNA_int_set_array(op->ptr, "location", location);
+
+               sample_color_exec(C, op);
+       }
+
+       WM_event_add_modal_handler(C, op);
+
+       return OPERATOR_RUNNING_MODAL;
+}
+
+static int sample_color_modal(bContext *C, wmOperator *op, wmEvent *event)
+{
+       ARegion *ar= CTX_wm_region(C);
+       int location[2];
+
+       switch(event->type) {
+               case LEFTMOUSE:
+               case RIGHTMOUSE: // XXX hardcoded
+                       return OPERATOR_FINISHED;
+               case MOUSEMOVE:
+                       if(ar) {
+                               location[0]= event->x - ar->winrct.xmin;
+                               location[1]= event->y - ar->winrct.ymin;
+                               RNA_int_set_array(op->ptr, "location", location);
+
+                               sample_color_exec(C, op);
+                       }
+                       break;
+       }
 
-       return sample_color_exec(C, op);
+       return OPERATOR_RUNNING_MODAL;
 }
 
 void PAINT_OT_sample_color(wmOperatorType *ot)
@@ -5153,6 +5208,7 @@ void PAINT_OT_sample_color(wmOperatorType *ot)
        /* api callbacks */
        ot->exec= sample_color_exec;
        ot->invoke= sample_color_invoke;
+       ot->modal= sample_color_modal;
        ot->poll= image_paint_poll;
 
        /* flags */
@@ -5274,7 +5330,7 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
                toggle_paint_cursor(C, 1);
        }
 
-       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
        WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene);
 
        return OPERATOR_FINISHED;
@@ -5300,16 +5356,16 @@ static int texture_paint_radial_control_invoke(bContext *C, wmOperator *op, wmEv
 {
        ToolSettings *ts = CTX_data_scene(C)->toolsettings;
        toggle_paint_cursor(C, !ts->imapaint.paintcursor);
-       brush_radial_control_invoke(op, paint_brush(&ts->imapaint.paint), 0.5);
+       brush_radial_control_invoke(op, paint_brush(&ts->imapaint.paint), 1);
        return WM_radial_control_invoke(C, op, event);
 }
 
 static int texture_paint_radial_control_exec(bContext *C, wmOperator *op)
 {
        Brush *brush = paint_brush(&CTX_data_scene(C)->toolsettings->imapaint.paint);
-       int ret = brush_radial_control_exec(op, brush, 2);
-       char str[256];
-       WM_radial_control_string(op, str, 256);
+       int ret = brush_radial_control_exec(op, brush, 1);
+       char str[64];
+       WM_radial_control_string(op, str, sizeof(str));
 
        WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush);
 
@@ -5343,7 +5399,7 @@ void PAINT_OT_texture_paint_radial_control(wmOperatorType *ot)
        ot->poll= texture_paint_poll;
        
        /* flags */
-       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
 }
 
 
@@ -5357,13 +5413,11 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
 {
        Image *image= BLI_findlink(&CTX_data_main(C)->image, RNA_enum_get(op->ptr, "image"));
        Scene *scene= CTX_data_scene(C);
-       ProjPaintState ps;
+       ProjPaintState ps= {0};
        int orig_brush_size;
        IDProperty *idgroup;
        IDProperty *view_data= NULL;
 
-       memset(&ps, 0, sizeof(ps));
-
        project_state_init(C, OBACT, &ps);
 
        if(ps.ob==NULL || ps.ob->type != OB_MESH) {
@@ -5412,21 +5466,21 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
        /* override */
        ps.is_texbrush= 0;
        ps.is_airbrush= 1;
-       orig_brush_size= ps.brush->size;
-       ps.brush->size= 32; /* cover the whole image */
+       orig_brush_size= brush_size(ps.brush);
+       brush_set_size(ps.brush, 32); /* cover the whole image */
 
        ps.tool= PAINT_TOOL_DRAW; /* so pixels are initialized with minimal info */
 
        scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING;
 
-       undo_paint_push_begin(UNDO_PAINT_IMAGE, "Image Paint",
+       undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
                image_undo_restore, image_undo_free);
 
        /* allocate and initialize spacial data structures */
        project_paint_begin(&ps);
 
        if(ps.dm==NULL) {
-               ps.brush->size= orig_brush_size;
+               brush_set_size(ps.brush, orig_brush_size);
                return OPERATOR_CANCELLED;
        }
        else {
@@ -5450,7 +5504,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
        project_paint_end(&ps);
 
        scene->toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
-       ps.brush->size= orig_brush_size;
+       brush_set_size(ps.brush, orig_brush_size);
 
        return OPERATOR_FINISHED;
 }
@@ -5488,14 +5542,21 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
        int h= settings->imapaint.screen_grab_size[1];
        int maxsize;
 
-       RNA_string_get(op->ptr, "filename", filename);
+       RNA_string_get(op->ptr, "filepath", filename);
 
        glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
 
        if(w > maxsize) w= maxsize;
        if(h > maxsize) h= maxsize;
 
-       ibuf= ED_view3d_draw_offscreen_imbuf(CTX_data_scene(C), CTX_wm_view3d(C), CTX_wm_region(C), w, h);
+       ibuf= ED_view3d_draw_offscreen_imbuf(CTX_data_scene(C), CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect);
+       if(!ibuf) {
+               /* Mostly happens when OpenGL offscreen buffer was failed to create, */
+               /* but could be other reasons. Should be handled in the future. nazgul */
+               BKE_report(op->reports, RPT_ERROR, "Failed to create OpenGL offscreen buffer.");
+               return OPERATOR_CANCELLED;
+       }
+
        image= BKE_add_image_imbuf(ibuf);
 
        if(image) {
@@ -5537,9 +5598,10 @@ void PAINT_OT_image_from_view(wmOperatorType *ot)
 
        /* api callbacks */
        ot->exec= texture_paint_image_from_view_exec;
+       ot->poll= ED_operator_region_view3d_active;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER;
 
-       RNA_def_string_file_name(ot->srna, "filename", "", FILE_MAX, "File Name", "Name of the file");
+       RNA_def_string_file_name(ot->srna, "filepath", "", FILE_MAX, "File Path", "Name of the file");
 }