projection painting clone tool - gives a similar work flow to cloning in the gimp...
authorCampbell Barton <ideasman42@gmail.com>
Wed, 5 Nov 2008 14:45:54 +0000 (14:45 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 5 Nov 2008 14:45:54 +0000 (14:45 +0000)
todo...
* pixel interpolation.
* clone option can currently only be set from the image paint panel.
* only initialize clone pixels under the mouse.
* overlap between source/target while painting could cause problems. need to look into this.

also fixed some cashes in painting normally.

source/blender/src/imagepaint.c

index 16bf5315020864b5fe5498e48bee7ca78d95f932..119e174a71d647ce634b324458ebf627ce86f99f 100644 (file)
@@ -145,8 +145,9 @@ typedef struct ImagePaintState {
 #define PROJ_FACE_SEAM4        1<<5
 
 
-#define PROJ_BUCKET_NULL       0
-#define PROJ_BUCKET_INIT       1
+#define PROJ_BUCKET_NULL               0
+#define PROJ_BUCKET_INIT               1<<0
+// #define PROJ_BUCKET_CLONE_INIT      1<<1
 
 /* only for readability */
 #define PROJ_BUCKET_LEFT               0
@@ -217,8 +218,10 @@ typedef struct ProjectPixel {
 } ProjectPixel;
 
 typedef struct ProjectPixelClone {
-       struct ProjectPixel;
-       void *source;
+       struct ProjectPixel __pp;
+       char backbuf[4];        /* TODO - float buffer? */
+       char clonebuf[4];
+       //void *source;         /* pointer to source pixels */
 } ProjectPixelClone;
 
 /* Finish projection painting structs */
@@ -396,15 +399,144 @@ static int project_paint_BucketOffset(ProjectPaintState *ps, float *projCo2D)
                (       (       (int)(( (projCo2D[1] - ps->viewMin2D[1])  / ps->viewHeight) * ps->bucketsY)) * ps->bucketsX );
 }
 
+static int project_paint_BucketOffsetSafe(ProjectPaintState *ps, float *projCo2D)
+{
+       int bucket_index = project_paint_BucketOffset(ps, projCo2D);
+       
+       if (bucket_index < 0 || bucket_index >= ps->bucketsX*ps->bucketsY) {    
+               return -1;
+       } else {
+               return bucket_index;
+       }
+}
+
+/* assume they intersect */
+static void BarryCentricWeights2f(float v1[2], float v2[2], float v3[2], float pt[2], float w[3]) {
+       float wtot;
+       w[0] = AreaF2Dfl(v2, v3, pt);
+       w[1] = AreaF2Dfl(v3, v1, pt);
+       w[2] = AreaF2Dfl(v1, v2, pt);
+       wtot = w[0]+w[1]+w[2];
+       w[0]/=wtot;
+       w[1]/=wtot;
+       w[2]/=wtot;
+}
+
+static float tri_depth_2d(float v1[3], float v2[3], float v3[3], float pt[2], float w[3])
+{
+       BarryCentricWeights2f(v1,v2,v3,pt,w);
+       return (v1[2]*w[0]) + (v2[2]*w[1]) + (v3[2]*w[2]);
+}
+
+
+/* return the topmost face  in screen coords index or -1
+ * bucket_index can be -1 if we dont know it to begin with */
+static int screenco_pickface(ProjectPaintState *ps, float pt[2], float w[3], int *side) {
+       LinkNode *node;
+       float w_tmp[3];
+       float *v1, *v2, *v3, *v4;
+       int bucket_index;
+       int face_index;
+       int best_side = -1;
+       int best_face_index = -1;
+       float z_depth_best = MAXFLOAT, z_depth;
+       MFace *mf;
+       
+       bucket_index = project_paint_BucketOffsetSafe(ps, pt);
+       if (bucket_index==-1)
+               return -1;
+       
+       node = ps->projectFaces[bucket_index];
+       
+       /* we could return 0 for 1 face buckets, as long as this function assumes
+        * that the point its testing is only every originated from an existing face */
+       
+       while (node) {
+               face_index = (int)node->link;
+               mf = ps->dm_mface + face_index;
+               
+               v1 = ps->projectVertScreenCos[mf->v1];
+               v2 = ps->projectVertScreenCos[mf->v2];
+               v3 = ps->projectVertScreenCos[mf->v3];
+               
+               if ( IsectPT2Df(pt, v1, v2, v3) ) {
+                       z_depth = tri_depth_2d(v1,v2,v3,pt,w_tmp);
+                       if (z_depth < z_depth_best) {
+                               best_face_index = face_index;
+                               best_side = 0;
+                               z_depth_best = z_depth;
+                               VECCOPY(w, w_tmp);
+                       }
+               } else if (mf->v4) {
+                       v4 = ps->projectVertScreenCos[mf->v4];
+                       
+                       if ( IsectPT2Df(pt, v1, v3, v4) ) {
+                               z_depth = tri_depth_2d(v1,v3,v4,pt,w_tmp);
+                               if (z_depth < z_depth_best) {
+                                       best_face_index = face_index;
+                                       best_side = 1;
+                                       z_depth_best = z_depth;
+                                       VECCOPY(w, w_tmp);
+                               }
+                       }
+               }
+               
+               node = node->next;
+       }
+       
+       *side = best_side;
+       return best_face_index; /* will be -1 or a valid face */
+}
+
+/* bucket_index is optional, since in some cases we know it */
+static int screenco_pickcol(ProjectPaintState *ps, int bucket_index, float pt[2], char rgba[4])
+{
+       float w[3], uv[2];
+       int side;
+       int face_index;
+       MTFace *tf;
+       ImBuf *ibuf;
+       int x,y;
+       char *pixel;
+       
+       face_index = screenco_pickface(ps,pt,w, &side);
+       
+       if (face_index == -1)
+               return 0;
+       
+       tf = ps->dm_mtface + face_index;
+       
+       if (side==0) {
+               uv[0] = tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[2][0]*w[2];
+               uv[1] = tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[2][1]*w[2];
+       } else { /* QUAD */
+               uv[0] = tf->uv[0][0]*w[0] + tf->uv[2][0]*w[1] + tf->uv[3][0]*w[2];
+               uv[1] = tf->uv[0][1]*w[0] + tf->uv[2][1]*w[1] + tf->uv[3][1]*w[2];
+       }
+       
+       ibuf = BKE_image_get_ibuf((Image *)tf->tpage, NULL); /* TODO - this may be slow */
+       
+       x = uv[0]*ibuf->x;
+       y = uv[1]*ibuf->y;
+       
+       if (x<0 || x>=ibuf->x  ||  y<0 || y>=ibuf->y) return 0;
+       
+       pixel = (( char * ) ibuf->rect) + (( x + y * ibuf->x ) * 4);
+       
+       rgba[0] = pixel[0];
+       rgba[1] = pixel[1];
+       rgba[2] = pixel[2];
+       rgba[3] = pixel[3];
+       return 1;
+}
+
 /* return...
  * 0   : no occlusion
  * -1  : no occlusion but 2D intersection is true (avoid testing the other half of a quad)
  * 1   : occluded */
 
-static int screenco_tri_pt_occlude(float *pt, float *v1, float *v2, float *v3)
+static int screenco_tri_pt_occlude(float pt[3], float v1[3], float v2[3], float v3[3])
 {
-       float w1, w2, w3, wtot; /* weights for converting the pixel into 3d worldspace coords */
-       
        /* if all are behind us, return false */
        if(v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2])
                return 0;
@@ -419,13 +551,9 @@ static int screenco_tri_pt_occlude(float *pt, float *v1, float *v2, float *v3)
        if(     v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) {
                return 1;
        } else {
+               float w[3];
                /* we intersect? - find the exact depth at the point of intersection */
-               w1 = AreaF2Dfl(v2, v3, pt);
-               w2 = AreaF2Dfl(v3, v1, pt);
-               w3 = AreaF2Dfl(v1, v2, pt);
-               wtot = w1 + w2 + w3;
-               
-               if ((v1[2]*w1/wtot) + (v2[2]*w2/wtot) + (v3[2]*w3/wtot) < pt[2]) {
+               if (tri_depth_2d(v1,v2,v3,pt,w) < pt[2]) {
                        return 1; /* This point is occluded by another face */
                }
        }
@@ -497,7 +625,7 @@ static int project_bucket_point_occluded(ProjectPaintState *ps, int bucket_index
 #define ISECT_TRUE 1
 #define ISECT_TRUE_P1 2
 #define ISECT_TRUE_P2 3
-static int project_scanline_isect(float *p1, float *p2, float y_level, float *x_isect)
+static int project_scanline_isect(float p1[2], float p2[2], float y_level, float *x_isect)
 {
        if (y_level==p1[1]) {
                *x_isect = p1[0];
@@ -519,7 +647,7 @@ static int project_scanline_isect(float *p1, float *p2, float y_level, float *x_
        }
 }
 
-static int project_face_scanline(ProjectScanline *sc, float y_level, float *v1, float *v2, float *v3, float *v4)
+static int project_face_scanline(ProjectScanline *sc, float y_level, float v1[2], float v2[2], float v3[2], float v4[2])
 {      
        /* Create a scanlines for the face at this Y level 
         * triangles will only ever have 1 scanline, quads may have 2 */
@@ -614,7 +742,7 @@ static int project_face_scanline(ProjectScanline *sc, float y_level, float *v1,
        return totscanlines;
 }
 
-static int cmp_uv(float *vec2a, float *vec2b)
+static int cmp_uv(float vec2a[2], float vec2b[2])
 {
        return ((fabs(vec2a[0]-vec2b[0]) < 0.0001) && (fabs(vec2a[1]-vec2b[1]) < 0.0001)) ? 1:0;
 }
@@ -712,7 +840,7 @@ static float angleToLength(float angle)
 }
 
 /* return zero if there is no area in the returned rectangle */
-static int uv_image_rect(float *uv1, float *uv2, float *uv3, float *uv4, int *min_px, int *max_px, int x_px, int y_px, int is_quad)
+static int uv_image_rect(float uv1[2], float uv2[2], float uv3[2], float uv4[2], int min_px[2], int max_px[2], int x_px, int y_px, int is_quad)
 {
        float min_uv[2], max_uv[2]; /* UV bounds */
        int i;
@@ -862,41 +990,29 @@ static float lambda_cp_line2(float p[2], float l1[2], float l2[2])
 }
 
 static screen_px_from_ortho(
-               ProjectPaintState *ps, float *uv,
-               float *v1co, float *v2co, float *v3co, /* Screenspace coords */
-               float *uv1co, float *uv2co, float *uv3co,
-               float *pixelScreenCo )
+               ProjectPaintState *ps, float uv[2],
+               float v1co[3], float v2co[3], float v3co[3], /* Screenspace coords */
+               float uv1co[2], float uv2co[2], float uv3co[2],
+               float pixelScreenCo[4] )
 {
-       float w1, w2, w3, wtot; /* weights for converting the pixel into 3d screenspace coords */
-       w1 = AreaF2Dfl(uv2co, uv3co, uv);
-       w2 = AreaF2Dfl(uv3co, uv1co, uv);
-       w3 = AreaF2Dfl(uv1co, uv2co, uv);
-       
-       wtot = w1 + w2 + w3;
-       w1 /= wtot; w2 /= wtot; w3 /= wtot;
-       
-       pixelScreenCo[0] = v1co[0]*w1 + v2co[0]*w2 + v3co[0]*w3;
-       pixelScreenCo[1] = v1co[1]*w1 + v2co[1]*w2 + v3co[1]*w3;
-       pixelScreenCo[2] = v1co[2]*w1 + v2co[2]*w2 + v3co[2]*w3;        
+       float w[3];
+       BarryCentricWeights2f(uv1co,uv2co,uv3co,uv,w);
+       pixelScreenCo[0] = v1co[0]*w[0] + v2co[0]*w[1] + v3co[0]*w[2];
+       pixelScreenCo[1] = v1co[1]*w[0] + v2co[1]*w[1] + v3co[1]*w[2];
+       pixelScreenCo[2] = v1co[2]*w[0] + v2co[2]*w[1] + v3co[2]*w[2];  
 }
 
 static screen_px_from_persp(
-               ProjectPaintState *ps, float *uv,
-               float *v1co, float *v2co, float *v3co, /* Worldspace coords */
-               float *uv1co, float *uv2co, float *uv3co,
-               float *pixelScreenCo )
+               ProjectPaintState *ps, float uv[2],
+               float v1co[3], float v2co[3], float v3co[3], /* Worldspace coords */
+               float uv1co[2], float uv2co[2], float uv3co[2],
+               float pixelScreenCo[4])
 {
-       float w1, w2, w3, wtot; /* weights for converting the pixel into 3d screenspace coords */
-       w1 = AreaF2Dfl(uv2co, uv3co, uv);
-       w2 = AreaF2Dfl(uv3co, uv1co, uv);
-       w3 = AreaF2Dfl(uv1co, uv2co, uv);
-       
-       wtot = w1 + w2 + w3;
-       w1 /= wtot; w2 /= wtot; w3 /= wtot;
-       
-       pixelScreenCo[0] = v1co[0]*w1 + v2co[0]*w2 + v3co[0]*w3;
-       pixelScreenCo[1] = v1co[1]*w1 + v2co[1]*w2 + v3co[1]*w3;
-       pixelScreenCo[2] = v1co[2]*w1 + v2co[2]*w2 + v3co[2]*w3;        
+       float w[3];
+       BarryCentricWeights2f(uv1co,uv2co,uv3co,uv,w);
+       pixelScreenCo[0] = v1co[0]*w[0] + v2co[0]*w[1] + v3co[0]*w[2];
+       pixelScreenCo[1] = v1co[1]*w[0] + v2co[1]*w[1] + v3co[1]*w[2];
+       pixelScreenCo[2] = v1co[2]*w[0] + v2co[2]*w[1] + v3co[2]*w[2];
        pixelScreenCo[3] = 1.0;
        
        Mat4MulVec4fl(ps->projectMat, pixelScreenCo);
@@ -908,10 +1024,13 @@ static screen_px_from_persp(
        pixelScreenCo[2] = pixelScreenCo[2]/pixelScreenCo[3]; /* Use the depth for bucket point occlusion */
 }
 
-/* can provide own own coords, use for seams when we want to bleed our from the original location */
 
+static void project_paint_bucket_init(ProjectPaintState *ps, int bucket_index);
+
+/* Only run this function once for new ProjectPixelClone's */
 #define pixel_size 4
-static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, float *uv,  int x, int y, int face_index, float *pixelScreenCo)
+
+static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, float uv[2], int x, int y, int face_index, float pixelScreenCo[4])
 {
        int bucket_index;
        
@@ -919,10 +1038,10 @@ static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, float
        
        ProjectPixel *projPixel;
        
-       bucket_index = project_paint_BucketOffset(ps, pixelScreenCo);
+       bucket_index = project_paint_BucketOffsetSafe(ps, pixelScreenCo);
        
        /* even though it should be clamped, in some cases it can still run over */
-       if (bucket_index < 0 || bucket_index >= ps->bucketsX * ps->bucketsY)
+       if (bucket_index==-1)
                return;
        
        /* Use viewMin2D to make (0,0) the bottom left of the bounds 
@@ -931,12 +1050,38 @@ static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, float
        /* Is this UV visible from the view? - raytrace */
        if (ps->projectIsOcclude==0 || !project_bucket_point_occluded(ps, bucket_index, face_index, pixelScreenCo)) {
                /* done with view3d_project_float inline */
-               projPixel = (ProjectPixel *)BLI_memarena_alloc( ps->projectArena, sizeof(ProjectPixel) );
+               if (ps->tool==PAINT_TOOL_CLONE) {
+                       float co[2];
+                       
+                       projPixel = (ProjectPixel *)BLI_memarena_alloc(ps->projectArena, sizeof(ProjectPixelClone));
+                       projPixel->pixel = (( char * ) ibuf->rect) + (( x + y * ibuf->x ) * pixel_size);
+                       VECCOPY2D(projPixel->projCo2D, pixelScreenCo);
+                       
+                       /* copy pixel color to backbuf */
+                       memcpy( &(((ProjectPixelClone *)projPixel)->backbuf), projPixel->pixel, pixel_size);
+                       //((ProjectPixelClone *)projPixel)->source = NULL; /* must be set later */
+                       
+                       
+                       /* Initialize clone pixels - note that this is a bit of a waste since some of these are being indirectly initialized :/ */
+                       /* TODO - possibly only run this for directly ativated buckets when cloning */
+                       Vec2Subf(co, projPixel->projCo2D, ps->cloneOfs);
+                               
+                       /* 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(...) */
+                       if (!screenco_pickcol(ps, bucket_index, co, ((ProjectPixelClone *)projPixel)->clonebuf)) {
+                               ((ProjectPixelClone *)projPixel)->clonebuf[3] = 0; /* zero alpha - ignore */
+                       }
+
+               } else {
+                       projPixel = (ProjectPixel *)BLI_memarena_alloc(ps->projectArena, sizeof(ProjectPixel));
+                       projPixel->pixel = (( char * ) ibuf->rect) + (( x + y * ibuf->x ) * pixel_size);
+                       VECCOPY2D(projPixel->projCo2D, pixelScreenCo);
+               }
                
                /* screenspace unclamped */
-               VECCOPY2D(projPixel->projCo2D, pixelScreenCo);
                
-               projPixel->pixel = (( char * ) ibuf->rect) + (( x + y * ibuf->x ) * pixel_size);
+               
+               
                
 #ifdef PROJ_DEBUG_PAINT
                projPixel->pixel[1] = 0;
@@ -1235,11 +1380,11 @@ static void project_paint_face_init(ProjectPaintState *ps, int face_index, ImBuf
 static void project_paint_rect(ProjectPaintState *ps, float min[2], float max[2], int bucket_min[2], int bucket_max[2])
 {
        /* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */
-       bucket_min[0] = (int)(((float)(min[0] - ps->viewMin2D[0]) / ps->viewWidth) * ps->bucketsX) + 0.5;
+       bucket_min[0] = (int)(((float)(min[0] - ps->viewMin2D[0]) / ps->viewWidth) * ps->bucketsX) + 0.5; /* these offsets of 0.5 and 1.5 seem odd but they are correct */
        bucket_min[1] = (int)(((float)(min[1] - ps->viewMin2D[1]) / ps->viewHeight) * ps->bucketsY) + 0.5;
        
-       bucket_max[0] = (int)(((float)(max[0] - ps->viewMin2D[0]) / ps->viewWidth) * ps->bucketsX) + 0.5;
-       bucket_max[1] = (int)(((float)(max[1] - ps->viewMin2D[1]) / ps->viewHeight) * ps->bucketsY) + 0.5;      
+       bucket_max[0] = (int)(((float)(max[0] - ps->viewMin2D[0]) / ps->viewWidth) * ps->bucketsX) + 1.5;
+       bucket_max[1] = (int)(((float)(max[1] - ps->viewMin2D[1]) / ps->viewHeight) * ps->bucketsY) + 1.5;      
        
        /* incase the rect is outside the mesh 2d bounds */
        CLAMP(bucket_min[0], 0, ps->bucketsX);
@@ -1252,7 +1397,7 @@ static void project_paint_rect(ProjectPaintState *ps, float min[2], float max[2]
 static void project_bucket_bounds(ProjectPaintState *ps, int bucket_x, int bucket_y, float bucket_bounds[4])
 {
        bucket_bounds[ PROJ_BUCKET_LEFT ] =             ps->viewMin2D[0]+((bucket_x)*(ps->viewWidth / ps->bucketsX));           /* left */
-       bucket_bounds[ PROJ_BUCKET_RIGHT ] =            ps->viewMin2D[0]+((bucket_x+1)*(ps->viewWidth / ps->bucketsX)); /* right */
+       bucket_bounds[ PROJ_BUCKET_RIGHT ] =    ps->viewMin2D[0]+((bucket_x+1)*(ps->viewWidth / ps->bucketsX)); /* right */
        
        bucket_bounds[ PROJ_BUCKET_BOTTOM ] =   ps->viewMin2D[1]+((bucket_y)*(ps->viewHeight / ps->bucketsY));          /* bottom */
        bucket_bounds[ PROJ_BUCKET_TOP ] =              ps->viewMin2D[1]+((bucket_y+1)*(ps->viewHeight  / ps->bucketsY));       /* top */
@@ -1260,7 +1405,6 @@ static void project_bucket_bounds(ProjectPaintState *ps, int bucket_x, int bucke
 
 static void project_paint_bucket_init(ProjectPaintState *ps, int bucket_index)
 {
-       
        LinkNode *node;
        int face_index;
        ImBuf *ibuf;
@@ -1268,7 +1412,7 @@ static void project_paint_bucket_init(ProjectPaintState *ps, int bucket_index)
        
        /*printf("\tinit bucket %d\n", bucket_index);*/
        
-       ps->projectBucketFlags[bucket_index] = PROJ_BUCKET_INIT; 
+       ps->projectBucketFlags[bucket_index] |= PROJ_BUCKET_INIT; 
        
        if ((node = ps->projectFaces[bucket_index])) {
                do {
@@ -1288,6 +1432,7 @@ static void project_paint_bucket_init(ProjectPaintState *ps, int bucket_index)
        }
 }
 
+
 /* We want to know if a bucket and a face overlap in screenspace
  * 
  * Note, if this ever returns false positives its not that bad, since a face in the bounding area will have its pixels
@@ -1519,10 +1664,14 @@ static void project_paint_begin( ProjectPaintState *ps, short mval[2])
        if (ps->tool == PAINT_TOOL_CLONE) {
                float *curs= give_cursor();
                VECCOPY(projCo, curs); /* TODO - what if were in local view? - get some better way */
+               Mat4MulVec4fl(ps->ob->imat, projCo);
                projCo[3] = 1.0;
                Mat4MulVec4fl(ps->projectMat, projCo);
-               ps->cloneOfs[0] = mval[0] - ((float)(curarea->winx/2.0)+(curarea->winx/2.0)*projCo[0]/projCo[3]);       
+               ps->cloneOfs[0] = mval[0] - ((float)(curarea->winx/2.0)+(curarea->winx/2.0)*projCo[0]/projCo[3]);
                ps->cloneOfs[1] = mval[1] - ((float)(curarea->winy/2.0)+(curarea->winy/2.0)*projCo[1]/projCo[3]);
+               
+               // printf("%f %f   %f %f %f\n", ps->cloneOfs[0], ps->cloneOfs[1], curs[0], curs[1], curs[2]);
+               
        }
        
        /* If this border is not added we get artifacts for faces that
@@ -2080,7 +2229,7 @@ static int project_bucket_circle_isect(ProjectPaintState *ps, int bucket_x, int
        {
                return 1;
        }
-       
+        
        /* out of bounds left */
        if (cent[0] < bucket_bounds[PROJ_BUCKET_LEFT]) {
                /* lower left out of radius test */
@@ -2165,6 +2314,9 @@ static int imapaint_paint_sub_stroke_project(ProjectPaintState *ps, BrushPainter
                                        /* This bucket may hold some uninitialized faces, initialize it */
                                        project_paint_bucket_init(ps, bucket_index);
                                }
+                               
+                               /* TODO - we may want to init clone data in a seperate to project_paint_bucket_init
+                                * so we dont go overboard and init too many clone pixels  */
 
                                if ((node = ps->projectBuckets[bucket_index])) {
                                
@@ -2179,26 +2331,52 @@ static int imapaint_paint_sub_stroke_project(ProjectPaintState *ps, BrushPainter
                                                
                                                /*if (dist < s->brush->size) {*/ /* correct but uses a sqrt */
                                                if (dist_nosqrt < brush_size_sqared) {
-                                               
-                                                       brush_sample_tex(ps->brush, projPixel->projCo2D, rgba);
                                                        
                                                        dist = (float)sqrt(dist_nosqrt);
                                                        
-                                                       alpha = rgba[3]*brush_sample_falloff(ps->brush, dist);
-                                                       
-                                                       if (alpha <= 0.0) {
-                                                               /* do nothing */
+                                                       if (ps->tool==PAINT_TOOL_CLONE) { //&& ((ProjectPixelClone*)projPixel)->source )  {
+                                                               
+                                                               alpha = brush_sample_falloff(ps->brush, dist);
+                                                               
+                                                               if (((char *)((ProjectPixelClone*)projPixel)->clonebuf)[3]) {
+                                                                       projPixel->pixel[0] = FTOCHAR((((((char *)((ProjectPixelClone*)projPixel)->clonebuf)[0]/255.0) * alpha) + (((projPixel->pixel[0])/255.0)*(1.0-alpha))));
+                                                                       projPixel->pixel[1] = FTOCHAR((((((char *)((ProjectPixelClone*)projPixel)->clonebuf)[1]/255.0) * alpha) + (((projPixel->pixel[1])/255.0)*(1.0-alpha))));
+                                                                       projPixel->pixel[2] = FTOCHAR((((((char *)((ProjectPixelClone*)projPixel)->clonebuf)[2]/255.0) * alpha) + (((projPixel->pixel[2])/255.0)*(1.0-alpha))));
+                                                               }
+                                                               
+#if 0
+                                                               if (alpha <= 0.0) {
+                                                                       /* do nothing */
+                                                               } else {
+                                                                       if (alpha >= 1.0) {
+                                                                               projPixel->pixel[0] = FTOCHAR(rgba[0]*ps->brush->rgb[0]);
+                                                                               projPixel->pixel[1] = FTOCHAR(rgba[1]*ps->brush->rgb[1]);
+                                                                               projPixel->pixel[2] = FTOCHAR(rgba[2]*ps->brush->rgb[2]);
+                                                                       } else {
+                                                                               projPixel->pixel[0] = FTOCHAR(((rgba[0]*ps->brush->rgb[0])*alpha) + (((projPixel->pixel[0])/255.0)*(1.0-alpha)));
+                                                                               projPixel->pixel[1] = FTOCHAR(((rgba[1]*ps->brush->rgb[1])*alpha) + (((projPixel->pixel[1])/255.0)*(1.0-alpha)));
+                                                                               projPixel->pixel[2] = FTOCHAR(((rgba[2]*ps->brush->rgb[2])*alpha) + (((projPixel->pixel[2])/255.0)*(1.0-alpha)));
+                                                                       }
+                                                               } 
+#endif
                                                        } else {
-                                                               if (alpha >= 1.0) {
-                                                                       projPixel->pixel[0] = FTOCHAR(rgba[0]*ps->brush->rgb[0]);
-                                                                       projPixel->pixel[1] = FTOCHAR(rgba[1]*ps->brush->rgb[1]);
-                                                                       projPixel->pixel[2] = FTOCHAR(rgba[2]*ps->brush->rgb[2]);
+                                                               brush_sample_tex(ps->brush, projPixel->projCo2D, rgba);
+                                                               alpha = rgba[3]*brush_sample_falloff(ps->brush, dist);
+                                                               
+                                                               if (alpha <= 0.0) {
+                                                                       /* do nothing */
                                                                } else {
-                                                                       projPixel->pixel[0] = FTOCHAR(((rgba[0]*ps->brush->rgb[0])*alpha) + (((projPixel->pixel[0])/255.0)*(1.0-alpha)));
-                                                                       projPixel->pixel[1] = FTOCHAR(((rgba[1]*ps->brush->rgb[1])*alpha) + (((projPixel->pixel[1])/255.0)*(1.0-alpha)));
-                                                                       projPixel->pixel[2] = FTOCHAR(((rgba[2]*ps->brush->rgb[2])*alpha) + (((projPixel->pixel[2])/255.0)*(1.0-alpha)));
-                                                               }
-                                                       } 
+                                                                       if (alpha >= 1.0) {
+                                                                               projPixel->pixel[0] = FTOCHAR(rgba[0]*ps->brush->rgb[0]);
+                                                                               projPixel->pixel[1] = FTOCHAR(rgba[1]*ps->brush->rgb[1]);
+                                                                               projPixel->pixel[2] = FTOCHAR(rgba[2]*ps->brush->rgb[2]);
+                                                                       } else {
+                                                                               projPixel->pixel[0] = FTOCHAR(((rgba[0]*ps->brush->rgb[0])*alpha) + (((projPixel->pixel[0])/255.0)*(1.0-alpha)));
+                                                                               projPixel->pixel[1] = FTOCHAR(((rgba[1]*ps->brush->rgb[1])*alpha) + (((projPixel->pixel[1])/255.0)*(1.0-alpha)));
+                                                                               projPixel->pixel[2] = FTOCHAR(((rgba[2]*ps->brush->rgb[2])*alpha) + (((projPixel->pixel[2])/255.0)*(1.0-alpha)));
+                                                                       }
+                                                               } 
+                                                       }
                                                        
                                                        if (last_index != projPixel->image_index) {
                                                                last_index = projPixel->image_index;
@@ -2336,13 +2514,19 @@ void imagepaint_paint(short mousebutton, short texpaint)
 
        if(!settings->imapaint.brush)
                return;
-
+       
+       project = texpaint;
+       
+       
+       if (G.qual & LR_CTRLKEY) {
+               mouse_cursor();
+               return;
+       }
+       
        /* initialize state */
        memset(&s, 0, sizeof(s));
        memset(&ps, 0, sizeof(ps));
        
-       project = texpaint;
-       
        s.brush = settings->imapaint.brush;
        s.tool = settings->imapaint.tool;
        if(texpaint && (project==0) && (s.tool == PAINT_TOOL_CLONE))