- UNUSED macro wasn't throwing an error with GCC if a var become used.
[blender.git] / source / blender / editors / sculpt_paint / paint_image.c
index d223c4236906761307d2a34f82035ab14f44c44d..cd498c274cf3eea382f0da5134ef45705c2d66ca 100644 (file)
@@ -16,9 +16,8 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA       02111-1307, USA.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  * All rights reserved.
@@ -40,7 +39,7 @@
 #ifdef WIN32
 #include "BLI_winstuff.h"
 #endif
-#include "BLI_arithb.h"
+#include "BLI_math.h"
 #include "BLI_blenlib.h"
 #include "BLI_dynstr.h"
 #include "BLI_linklist.h"
 #include "IMB_imbuf.h"
 #include "IMB_imbuf_types.h"
 
-#include "DNA_brush_types.h"
-#include "DNA_image_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
-#include "DNA_node_types.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_userdef_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_windowmanager_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"
+#include "BKE_library.h"
 
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
 
-#include "UI_interface.h"
 #include "UI_view2d.h"
 
 #include "ED_image.h"
-#include "ED_object.h"
 #include "ED_screen.h"
+#include "ED_sculpt.h"
 #include "ED_view3d.h"
 
 #include "WM_api.h"
@@ -93,6 +84,7 @@
 
 #include "RNA_access.h"
 #include "RNA_define.h"
+#include "RNA_enum_types.h"
 
 #include "GPU_draw.h"
 
 #define IMAPAINT_TILE_SIZE                     (1 << IMAPAINT_TILE_BITS)
 #define IMAPAINT_TILE_NUMBER(size)     (((size)+IMAPAINT_TILE_SIZE-1) >> IMAPAINT_TILE_BITS)
 
-#define MAXUNDONAME    64
-
 static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint);
 
 
@@ -145,6 +135,11 @@ typedef struct ImagePaintPartialRedraw {
        int enabled;
 } ImagePaintPartialRedraw;
 
+typedef struct ImagePaintRegion {
+       int destx, desty;
+       int srcx, srcy;
+       int width, height;
+} ImagePaintRegion;
 
 /* ProjectionPaint defines */
 
@@ -180,6 +175,14 @@ typedef struct ImagePaintPartialRedraw {
 #define PROJ_FACE_NOSEAM3      1<<6
 #define PROJ_FACE_NOSEAM4      1<<7
 
+#define PROJ_SRC_VIEW          1
+#define PROJ_SRC_IMAGE_CAM     2
+#define PROJ_SRC_IMAGE_VIEW    3
+
+#define PROJ_VIEW_DATA_ID "view_data"
+#define PROJ_VIEW_DATA_SIZE (4*4 + 4*4 + 3) /* viewmat + winmat + clipsta + clipend + is_ortho */
+
+
 /* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams
  * as this number approaches  1.0f the likelihood increases of float precision errors where
  * it is occluded by an adjacent face */
@@ -204,7 +207,7 @@ typedef struct ProjPaintImage {
        Image *ima;
        ImBuf *ibuf;
        ImagePaintPartialRedraw *partRedrawRect;
-       struct UndoTile **undoRect; /* only used to build undo tiles after painting */
+       void **undoRect; /* only used to build undo tiles after painting */
        int touch;
 } ProjPaintImage;
 
@@ -214,6 +217,7 @@ typedef struct ProjPaintState {
        RegionView3D *rv3d;
        ARegion *ar;
        Scene *scene;
+       int source; /* PROJ_SRC_**** */
 
        Brush *brush;
        short tool, blend;
@@ -223,12 +227,13 @@ typedef struct ProjPaintState {
        DerivedMesh    *dm;
        int                     dm_totface;
        int                     dm_totvert;
+       int                             dm_release;
        
        MVert              *dm_mvert;
        MFace              *dm_mface;
        MTFace             *dm_mtface;
        MTFace             *dm_mtface_clone;    /* other UV layer, use for cloning between layers */
-       MTFace             *dm_mtface_mask;
+       MTFace             *dm_mtface_stencil;
        
        /* projection painting only */
        MemArena *arena_mt[BLENDER_MAX_THREADS];/* for multithreading, the first item is sometimes used for non threaded cases too */
@@ -254,11 +259,12 @@ typedef struct ProjPaintState {
        float screenMax[2]; 
        float screen_width;                     /* Calculated from screenMin & screenMax */
        float screen_height;
+       int winx, winy;                         /* from the carea or from the projection render */
        
        /* options for projection painting */
        int do_layer_clone;
-       int do_layer_mask;
-       int do_layer_mask_inv;
+       int do_layer_stencil;
+       int do_layer_stencil_inv;
        
        short do_occlude;                       /* Use raytraced occlusion? - ortherwise will paint right through to the back*/
        short do_backfacecull;  /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */
@@ -281,6 +287,11 @@ typedef struct ProjPaintState {
        float viewPos[3];                       /* View location in object relative 3D space, so can compare to verts  */
        float clipsta, clipend;
        
+       /* reproject vars */
+       Image *reproject_image;
+       ImBuf *reproject_ibuf;
+
+
        /* threads */
        int thread_tot;
        int bucketMin[2];
@@ -331,32 +342,20 @@ typedef struct ProjPixelClone {
 
 /* Finish projection painting structs */
 
+typedef struct UndoImageTile {
+       struct UndoImageTile *next, *prev;
+
+       char idname[MAX_ID_NAME];       /* name instead of pointer*/
 
-typedef struct UndoTile {
-       struct UndoTile *next, *prev;
-       ID id;
        void *rect;
        int x, y;
-} UndoTile;
+} UndoImageTile;
 
-typedef struct UndoElem {
-       struct UndoElem *next, *prev;
-       char name[MAXUNDONAME];
-       uintptr_t undosize;
-
-       ImBuf *ibuf;
-       ListBase tiles;
-} UndoElem;
-
-static ListBase undobase = {NULL, NULL};
-static UndoElem *curundo = NULL;
 static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
 
 /* UNDO */
 
-/* internal functions */
-
-static void undo_copy_tile(UndoTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore)
+static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore)
 {
        /* copy or swap contents of tile->rect and region in ibuf->rect */
        IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x*IMAPAINT_TILE_SIZE,
@@ -373,49 +372,52 @@ static void undo_copy_tile(UndoTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int rest
                        tile->y*IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
 }
 
-static UndoTile *undo_init_tile(ID *id, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
+static void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
 {
-       UndoTile *tile;
+       ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+       UndoImageTile *tile;
        int allocsize;
+
+       for(tile=lb->first; tile; tile=tile->next)
+               if(tile->x == x_tile && tile->y == y_tile && strcmp(tile->idname, ima->id.name)==0)
+                       return tile->rect;
        
        if (*tmpibuf==NULL)
                *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat|IB_rect, 0);
        
-       tile= MEM_callocN(sizeof(UndoTile), "ImaUndoTile");
-       tile->id= *id;
+       tile= MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
+       strcpy(tile->idname, ima->id.name);
        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= MEM_mapallocN(allocsize, "ImaUndoRect");
+       tile->rect= MEM_mapallocN(allocsize, "UndeImageTile.rect");
 
        undo_copy_tile(tile, *tmpibuf, ibuf, 0);
-       curundo->undosize += allocsize;
+       undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
 
-       BLI_addtail(&curundo->tiles, tile);
+       BLI_addtail(lb, tile);
        
-       return tile;
+       return tile->rect;
 }
 
-static void undo_restore(UndoElem *undo)
+static void image_undo_restore(bContext *C, ListBase *lb)
 {
+       Main *bmain= CTX_data_main(C);
        Image *ima = NULL;
        ImBuf *ibuf, *tmpibuf;
-       UndoTile *tile;
-
-       if(!undo)
-               return;
+       UndoImageTile *tile;
 
        tmpibuf= IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
-                               IB_rectfloat|IB_rect, 0);
+                                                       IB_rectfloat|IB_rect, 0);
        
-       for(tile=undo->tiles.first; tile; tile=tile->next) {
+       for(tile=lb->first; tile; tile=tile->next) {
                /* find image based on name, pointer becomes invalid with global undo */
-               if(ima && strcmp(tile->id.name, ima->id.name)==0);
+               if(ima && strcmp(tile->idname, ima->id.name)==0);
                else {
-                       for(ima=G.main->image.first; ima; ima=ima->id.next)
-                               if(strcmp(tile->id.name, ima->id.name)==0)
+                       for(ima=bmain->image.first; ima; ima=ima->id.next)
+                               if(strcmp(tile->idname, ima->id.name)==0)
                                        break;
                }
 
@@ -434,117 +436,12 @@ static void undo_restore(UndoElem *undo)
        IMB_freeImBuf(tmpibuf);
 }
 
-static void undo_free(UndoElem *undo)
+static void image_undo_free(ListBase *lb)
 {
-       UndoTile *tile;
+       UndoImageTile *tile;
 
-       for(tile=undo->tiles.first; tile; tile=tile->next)
+       for(tile=lb->first; tile; tile=tile->next)
                MEM_freeN(tile->rect);
-       BLI_freelistN(&undo->tiles);
-}
-
-static void undo_imagepaint_push_begin(char *name)
-{
-       UndoElem *uel;
-       int nr;
-       
-       /* Undo push is split up in begin and end, the reason is that as painting
-        * happens more tiles are added to the list, and at the very end we know
-        * how much memory the undo used to remove old undo elements */
-
-       /* remove all undos after (also when curundo==NULL) */
-       while(undobase.last != curundo) {
-               uel= undobase.last;
-               undo_free(uel);
-               BLI_freelinkN(&undobase, uel);
-       }
-       
-       /* make new */
-       curundo= uel= MEM_callocN(sizeof(UndoElem), "undo file");
-       BLI_addtail(&undobase, uel);
-
-       /* name can be a dynamic string */
-       strncpy(uel->name, name, MAXUNDONAME-1);
-       
-       /* limit amount to the maximum amount*/
-       nr= 0;
-       uel= undobase.last;
-       while(uel) {
-               nr++;
-               if(nr==U.undosteps) break;
-               uel= uel->prev;
-       }
-       if(uel) {
-               while(undobase.first!=uel) {
-                       UndoElem *first= undobase.first;
-                       undo_free(first);
-                       BLI_freelinkN(&undobase, first);
-               }
-       }
-}
-
-static void undo_imagepaint_push_end()
-{
-       UndoElem *uel;
-       uintptr_t totmem, maxmem;
-
-       if(U.undomemory != 0) {
-               /* limit to maximum memory (afterwards, we can't know in advance) */
-               totmem= 0;
-               maxmem= ((uintptr_t)U.undomemory)*1024*1024;
-
-               uel= undobase.last;
-               while(uel) {
-                       totmem+= uel->undosize;
-                       if(totmem>maxmem) break;
-                       uel= uel->prev;
-               }
-
-               if(uel) {
-                       while(undobase.first!=uel) {
-                               UndoElem *first= undobase.first;
-                               undo_free(first);
-                               BLI_freelinkN(&undobase, first);
-                       }
-               }
-       }
-}
-
-void undo_imagepaint_step(int step)
-{
-       UndoElem *undo;
-
-       if(step==1) {
-               if(curundo==NULL);
-               else {
-                       if(G.f & G_DEBUG) printf("undo %s\n", curundo->name);
-                       undo_restore(curundo);
-                       curundo= curundo->prev;
-               }
-       }
-       else if(step==-1) {
-               if((curundo!=NULL && curundo->next==NULL) || undobase.first==NULL);
-               else {
-                       undo= (curundo && curundo->next)? curundo->next: undobase.first;
-                       undo_restore(undo);
-                       curundo= undo;
-                       if(G.f & G_DEBUG) printf("redo %s\n", undo->name);
-               }
-       }
-}
-
-void undo_imagepaint_clear(void)
-{
-       UndoElem *uel;
-       
-       uel= undobase.first;
-       while(uel) {
-               undo_free(uel);
-               uel= uel->next;
-       }
-
-       BLI_freelistN(&undobase);
-       curundo= NULL;
 }
 
 /* fast projection bucket array lookup, use the safe version for bound checking  */
@@ -576,64 +473,36 @@ 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]))
-
-static float AreaSignedF2Dfl(float *v1, float *v2, float *v3)
-{
-   return (float)(0.5f*((v1[0]-v2[0])*(v2[1]-v3[1]) +
-(v1[1]-v2[1])*(v3[0]-v2[0])));
-}
-
-static void BarycentricWeights2f(float pt[2], float v1[2], float v2[2], float v3[2], float w[3])
-{
-   float wtot_inv, wtot;
-
-   w[0] = AreaSignedF2Dfl(v2, v3, pt);
-   w[1] = AreaSignedF2Dfl(v3, v1, pt);
-   w[2] = AreaSignedF2Dfl(v1, v2, pt);
-   wtot = w[0]+w[1]+w[2];
-
-   if (wtot != 0.0f) {
-       wtot_inv = 1.0f/wtot;
-
-       w[0] = w[0]*wtot_inv;
-       w[1] = w[1]*wtot_inv;
-       w[2] = w[2]*wtot_inv;
-   }
-   else /* dummy values for zero area face */
-       w[0] = w[1] = w[2] = 1.0f/3.0f;
-}
-
 /* 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 BarycentricWeightsPersp2f(float pt[2], float v1[4], float v2[4], float v3[4], float w[3])
+static void barycentric_weights_v2_persp(float v1[4], float v2[4], float v3[4], float co[2], float w[3])
 {
    float wtot_inv, wtot;
 
-   w[0] = AreaSignedF2Dfl(v2, v3, pt) / v1[3];
-   w[1] = AreaSignedF2Dfl(v3, v1, pt) / v2[3];
-   w[2] = AreaSignedF2Dfl(v1, v2, pt) / v3[3];
+   w[0] = area_tri_signed_v2(v2, v3, co) / v1[3];
+   w[1] = area_tri_signed_v2(v3, v1, co) / v2[3];
+   w[2] = area_tri_signed_v2(v1, v2, co) / v3[3];
    wtot = w[0]+w[1]+w[2];
 
    if (wtot != 0.0f) {
-       wtot_inv = 1.0f/wtot;
+          wtot_inv = 1.0f/wtot;
 
-       w[0] = w[0]*wtot_inv;
-       w[1] = w[1]*wtot_inv;
-       w[2] = w[2]*wtot_inv;
+          w[0] = w[0]*wtot_inv;
+          w[1] = w[1]*wtot_inv;
+          w[2] = w[2]*wtot_inv;
    }
    else /* dummy values for zero area face */
-       w[0] = w[1] = w[2] = 1.0f/3.0f;
+          w[0] = w[1] = w[2] = 1.0f/3.0f;
 }
 
 static float VecZDepthOrtho(float pt[2], float v1[3], float v2[3], float v3[3], float w[3])
 {
-       BarycentricWeights2f(pt, v1, v2, v3, w);
+       barycentric_weights_v2(v1, v2, v3, pt, w);
        return (v1[2]*w[0]) + (v2[2]*w[1]) + (v3[2]*w[2]);
 }
 
 static float VecZDepthPersp(float pt[2], float v1[3], float v2[3], float v3[3], float w[3])
 {
-       BarycentricWeightsPersp2f(pt, v1, v2, v3, w);
+       barycentric_weights_v2_persp(v1, v2, v3, pt, w);
        return (v1[2]*w[0]) + (v2[2]*w[1]) + (v3[2]*w[2]);
 }
 
@@ -668,7 +537,7 @@ static int project_paint_PickFace(const ProjPaintState *ps, float pt[2], float w
                v2= ps->screenCoords[mf->v2];
                v3= ps->screenCoords[mf->v3];
                
-               if (IsectPT2Df(pt, v1, v2, v3)) {
+               if (isect_point_tri_v2(pt, v1, v2, v3)) {
                        if (ps->is_ortho)       z_depth= VecZDepthOrtho(pt, v1, v2, v3, w_tmp);
                        else                            z_depth= VecZDepthPersp(pt, v1, v2, v3, w_tmp);
                        
@@ -682,7 +551,7 @@ static int project_paint_PickFace(const ProjPaintState *ps, float pt[2], float w
                else if (mf->v4) {
                        v4= ps->screenCoords[mf->v4];
                        
-                       if (IsectPT2Df(pt, v1, v3, v4)) {
+                       if (isect_point_tri_v2(pt, v1, v3, v4)) {
                                if (ps->is_ortho)       z_depth= VecZDepthOrtho(pt, v1, v3, v4, w_tmp);
                                else                            z_depth= VecZDepthPersp(pt, v1, v3, v4, w_tmp);
 
@@ -733,10 +602,10 @@ static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float
        tf = ps->dm_mtface + face_index;
        
        if (side == 0) {
-               Vec2Lerp3f(uv, tf->uv[0], tf->uv[1], tf->uv[2], w);
+               interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[1], tf->uv[2], w);
        }
        else { /* QUAD */
-               Vec2Lerp3f(uv, tf->uv[0], tf->uv[2], tf->uv[3], w);
+               interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[2], tf->uv[3], w);
        }
        
        ibuf = tf->tpage->ibufs.first; /* we must have got the imbuf before getting here */
@@ -768,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;
                
@@ -808,7 +677,7 @@ static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float
  *  0  : no occlusion
  * -1  : no occlusion but 2D intersection is true (avoid testing the other half of a quad)
  *  1  : occluded
-    2  : occluded with w[3] weights set (need to know in some cases) */
+       2       : occluded with w[3] weights set (need to know in some cases) */
 
 static int project_paint_occlude_ptv(float pt[3], float v1[3], float v2[3], float v3[3], float w[3], int is_ortho)
 {
@@ -817,7 +686,7 @@ static int project_paint_occlude_ptv(float pt[3], float v1[3], float v2[3], floa
                return 0;
                
        /* do a 2D point in try intersection */
-       if (!IsectPT2Df(pt, v1, v2, v3))
+       if (!isect_point_tri_v2(pt, v1, v2, v3))
                return 0; /* we know there is  */
        
 
@@ -852,16 +721,15 @@ static int project_paint_occlude_ptv_clip(
                return ret;
 
        if (ret==1) { /* weights not calculated */
-               if (ps->is_ortho)       BarycentricWeights2f(pt, v1, v2, v3, w);
-               else                            BarycentricWeightsPersp2f(pt, v1, v2, v3, w);
+               if (ps->is_ortho)       barycentric_weights_v2(v1, v2, v3, pt, w);
+               else                            barycentric_weights_v2_persp(v1, v2, v3, pt, w);
        }
 
        /* Test if we're in the clipped area, */
-       if (side)       VecLerp3f(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
-       else            VecLerp3f(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
+       if (side)       interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
+       else            interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
        
-       Mat4MulVecfl(ps->ob->obmat, wco);
-       if(!view3d_test_clipping(ps->rv3d, wco)) {
+       if(!view3d_test_clipping(ps->rv3d, wco, 1)) {
                return 1;
        }
        
@@ -878,6 +746,7 @@ static int project_bucket_point_occluded(const ProjPaintState *ps, LinkNode *buc
        int face_index;
        int isect_ret;
        float w[3]; /* not needed when clipping */
+       const short do_clip= ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
        
        /* 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 */
@@ -887,14 +756,14 @@ static int project_bucket_point_occluded(const ProjPaintState *ps, LinkNode *buc
 
                if (orig_face != face_index) {
                        mf = ps->dm_mface + face_index;
-                       if(ps->rv3d->rflag & RV3D_CLIPPING)
+                       if(do_clip)
                                isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], 0);
                        else
                                isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], w, ps->is_ortho);
 
                        /* Note, if isect_ret==-1 then we dont want to test the other side of the quad */
                        if (isect_ret==0 && mf->v4) {
-                               if(ps->rv3d->rflag & RV3D_CLIPPING)
+                               if(do_clip)
                                        isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], 1);
                                else
                                        isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], w, ps->is_ortho);
@@ -1142,8 +1011,7 @@ 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_x_inv = 1.0f / (float)ibuf_x; 
-       float ibuf_y_inv = 1.0f / (float)ibuf_y; 
+       float ibuf_inv[2] = {1.0f / (float)ibuf_x, 1.0f / (float)ibuf_y};
        
        /* make UV's in pixel space so we can */
        puv[0][0] = orig_uv[0][0] * ibuf_x;
@@ -1161,84 +1029,76 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const fl
        }
        
        /* face edge directions */
-       Vec2Subf(dir1, puv[1], puv[0]);
-       Vec2Subf(dir2, puv[2], puv[1]);
-       Normalize2(dir1);
-       Normalize2(dir2);
+       sub_v2_v2v2(dir1, puv[1], puv[0]);
+       sub_v2_v2v2(dir2, puv[2], puv[1]);
+       normalize_v2(dir1);
+       normalize_v2(dir2);
        
        if (is_quad) {
-               Vec2Subf(dir3, puv[3], puv[2]);
-               Vec2Subf(dir4, puv[0], puv[3]);
-               Normalize2(dir3);
-               Normalize2(dir4);
+               sub_v2_v2v2(dir3, puv[3], puv[2]);
+               sub_v2_v2v2(dir4, puv[0], puv[3]);
+               normalize_v2(dir3);
+               normalize_v2(dir4);
        }
        else {
-               Vec2Subf(dir3, puv[0], puv[2]);
-               Normalize2(dir3);
+               sub_v2_v2v2(dir3, puv[0], puv[2]);
+               normalize_v2(dir3);
        }
-       
+
+       /* TODO - angle_normalized_v2v2(...) * (M_PI/180.0f)
+        * This is incorrect. Its already given radians but without it wont work.
+        * need to look into a fix - campbell */
        if (is_quad) {
-               a1 = AngleToLength(NormalizedVecAngle2_2D(dir4, dir1));
-               a2 = AngleToLength(NormalizedVecAngle2_2D(dir1, dir2));
-               a3 = AngleToLength(NormalizedVecAngle2_2D(dir2, dir3));
-               a4 = AngleToLength(NormalizedVecAngle2_2D(dir3, dir4));
+               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 = AngleToLength(NormalizedVecAngle2_2D(dir3, dir1));
-               a2 = AngleToLength(NormalizedVecAngle2_2D(dir1, dir2));
-               a3 = AngleToLength(NormalizedVecAngle2_2D(dir2, dir3));
+               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) {
-               Vec2Subf(no1, dir4, dir1);
-               Vec2Subf(no2, dir1, dir2);
-               Vec2Subf(no3, dir2, dir3);
-               Vec2Subf(no4, dir3, dir4);
-               Normalize2(no1);
-               Normalize2(no2);
-               Normalize2(no3);
-               Normalize2(no4);
-               Vec2Mulf(no1, a1*scaler);
-               Vec2Mulf(no2, a2*scaler);
-               Vec2Mulf(no3, a3*scaler);
-               Vec2Mulf(no4, a4*scaler);
-               Vec2Addf(outset_uv[0], puv[0], no1);
-               Vec2Addf(outset_uv[1], puv[1], no2);
-               Vec2Addf(outset_uv[2], puv[2], no3);
-               Vec2Addf(outset_uv[3], puv[3], no4);
-               outset_uv[0][0] *= ibuf_x_inv;
-               outset_uv[0][1] *= ibuf_y_inv;
-               
-               outset_uv[1][0] *= ibuf_x_inv;
-               outset_uv[1][1] *= ibuf_y_inv;
-               
-               outset_uv[2][0] *= ibuf_x_inv;
-               outset_uv[2][1] *= ibuf_y_inv;
-               
-               outset_uv[3][0] *= ibuf_x_inv;
-               outset_uv[3][1] *= ibuf_y_inv;
+               sub_v2_v2v2(no1, dir4, dir1);
+               sub_v2_v2v2(no2, dir1, dir2);
+               sub_v2_v2v2(no3, dir2, dir3);
+               sub_v2_v2v2(no4, dir3, dir4);
+               normalize_v2(no1);
+               normalize_v2(no2);
+               normalize_v2(no3);
+               normalize_v2(no4);
+               mul_v2_fl(no1, a1*scaler);
+               mul_v2_fl(no2, a2*scaler);
+               mul_v2_fl(no3, a3*scaler);
+               mul_v2_fl(no4, a4*scaler);
+               add_v2_v2v2(outset_uv[0], puv[0], no1);
+               add_v2_v2v2(outset_uv[1], puv[1], no2);
+               add_v2_v2v2(outset_uv[2], puv[2], no3);
+               add_v2_v2v2(outset_uv[3], puv[3], no4);
+               mul_v2_v2(outset_uv[0], ibuf_inv);
+               mul_v2_v2(outset_uv[1], ibuf_inv);
+               mul_v2_v2(outset_uv[2], ibuf_inv);
+               mul_v2_v2(outset_uv[3], ibuf_inv);
        }
        else {
-               Vec2Subf(no1, dir3, dir1);
-               Vec2Subf(no2, dir1, dir2);
-               Vec2Subf(no3, dir2, dir3);
-               Normalize2(no1);
-               Normalize2(no2);
-               Normalize2(no3);
-               Vec2Mulf(no1, a1*scaler);
-               Vec2Mulf(no2, a2*scaler);
-               Vec2Mulf(no3, a3*scaler);
-               Vec2Addf(outset_uv[0], puv[0], no1);
-               Vec2Addf(outset_uv[1], puv[1], no2);
-               Vec2Addf(outset_uv[2], puv[2], no3);
-               outset_uv[0][0] *= ibuf_x_inv;
-               outset_uv[0][1] *= ibuf_y_inv;
-               
-               outset_uv[1][0] *= ibuf_x_inv;
-               outset_uv[1][1] *= ibuf_y_inv;
-               
-               outset_uv[2][0] *= ibuf_x_inv;
-               outset_uv[2][1] *= ibuf_y_inv;
+               sub_v2_v2v2(no1, dir3, dir1);
+               sub_v2_v2v2(no2, dir1, dir2);
+               sub_v2_v2v2(no3, dir2, dir3);
+               normalize_v2(no1);
+               normalize_v2(no2);
+               normalize_v2(no3);
+               mul_v2_fl(no1, a1*scaler);
+               mul_v2_fl(no2, a2*scaler);
+               mul_v2_fl(no3, a3*scaler);
+               add_v2_v2v2(outset_uv[0], puv[0], no1);
+               add_v2_v2v2(outset_uv[1], puv[1], no2);
+               add_v2_v2v2(outset_uv[2], puv[2], no3);
+
+               mul_v2_v2(outset_uv[0], ibuf_inv);
+               mul_v2_v2(outset_uv[1], ibuf_inv);
+               mul_v2_v2(outset_uv[2], ibuf_inv);
        }
 }
 
@@ -1287,7 +1147,7 @@ static float lambda_cp_line2(const float p[2], const float l1[2], const float l2
        h[0] = p[0] - l1[0];
        h[1] = p[1] - l1[1];
        
-       return(Inp2f(u, h)/Inp2f(u, u));
+       return(dot_v2v2(u, h)/dot_v2v2(u, u));
 }
 
 
@@ -1302,8 +1162,8 @@ static void screen_px_from_ortho(
                float pixelScreenCo[4],
                float w[3])
 {
-       BarycentricWeights2f(uv, uv1co, uv2co, uv3co, w);
-       VecLerp3f(pixelScreenCo, v1co, v2co, v3co, w);
+       barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w);
+       interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w);
 }
 
 /* same as screen_px_from_ortho except we need to take into account
@@ -1317,7 +1177,7 @@ static void screen_px_from_persp(
 {
 
        float wtot_inv, wtot;
-       BarycentricWeights2f(uv, uv1co, uv2co, uv3co, w);
+       barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w);
        
        /* re-weight from the 4th coord of each screen vert */
        w[0] *= v1co[3];
@@ -1333,11 +1193,11 @@ 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 */
        
-       VecLerp3f(pixelScreenCo, v1co, v2co, v3co, w);
+       interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w);
 }
 
 static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const float w[3], int side, unsigned char rgba_ub[4], float rgba_f[4])
@@ -1355,7 +1215,7 @@ static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const
                uvCo3 =  (float *)tf_other->uv[2];
        }
        
-       Vec2Lerp3f(uv_other, uvCo1, uvCo2, uvCo3, w);
+       interp_v2_v2v2v2(uv_other, uvCo1, uvCo2, uvCo3, (float*)w);
        
        /* use */
        uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y);
@@ -1380,10 +1240,10 @@ float project_paint_uvpixel_mask(
        float mask;
        
        /* Image Mask */
-       if (ps->do_layer_mask) {
+       if (ps->do_layer_stencil) {
                /* another UV layers image is masking this one's */
                ImBuf *ibuf_other;
-               const MTFace *tf_other = ps->dm_mtface_mask + face_index;
+               const MTFace *tf_other = ps->dm_mtface_stencil + face_index;
                
                if (tf_other->tpage && (ibuf_other = BKE_image_get_ibuf(tf_other->tpage, NULL))) {
                        /* BKE_image_get_ibuf - TODO - this may be slow */
@@ -1399,7 +1259,7 @@ float project_paint_uvpixel_mask(
                                mask = ((rgba_ub[0]+rgba_ub[1]+rgba_ub[2])/(256*3.0f)) * (rgba_ub[3]/256.0f);
                        }
                        
-                       if (!ps->do_layer_mask_inv) /* matching the gimps layer mask black/white rules, white==full opacity */
+                       if (!ps->do_layer_stencil_inv) /* matching the gimps layer mask black/white rules, white==full opacity */
                                mask = (1.0f - mask);
 
                        if (mask == 0.0f) {
@@ -1431,11 +1291,11 @@ float project_paint_uvpixel_mask(
                no[0] = w[0]*no1[0] + w[1]*no2[0] + w[2]*no3[0];
                no[1] = w[0]*no1[1] + w[1]*no2[1] + w[2]*no3[1];
                no[2] = w[0]*no1[2] + w[1]*no2[2] + w[2]*no3[2];
-               Normalize(no);
+               normalize_v3(no);
                
                /* now we can use the normal as a mask */
                if (ps->is_ortho) {
-                       angle = NormalizedVecAngle2((float *)ps->viewDir, no);
+                       angle = angle_normalized_v3v3((float *)ps->viewDir, no);
                }
                else {
                        /* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */
@@ -1455,9 +1315,9 @@ float project_paint_uvpixel_mask(
                        viewDirPersp[0] = (ps->viewPos[0] - (w[0]*co1[0] + w[1]*co2[0] + w[2]*co3[0]));
                        viewDirPersp[1] = (ps->viewPos[1] - (w[0]*co1[1] + w[1]*co2[1] + w[2]*co3[1]));
                        viewDirPersp[2] = (ps->viewPos[2] - (w[0]*co1[2] + w[1]*co2[2] + w[2]*co3[2]));
-                       Normalize(viewDirPersp);
+                       normalize_v3(viewDirPersp);
                        
-                       angle = NormalizedVecAngle2(viewDirPersp, no);
+                       angle = angle_normalized_v3v3(viewDirPersp, no);
                }
                
                if (angle >= ps->normal_angle) {
@@ -1470,7 +1330,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;
 }
@@ -1577,10 +1437,10 @@ static ProjPixel *project_paint_uvpixel_init(
                }
                else {
                        float co[2];
-                       Vec2Subf(co, projPixel->projCoSS, (float *)ps->cloneOffset);
+                       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 */
@@ -1768,20 +1628,20 @@ static void scale_quad(float insetCos[4][3], float *origCos[4], const float inse
        cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1] + origCos[3][1]) / 4.0f;
        cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2] + origCos[3][2]) / 4.0f;
        
-       VecSubf(insetCos[0], origCos[0], cent);
-       VecSubf(insetCos[1], origCos[1], cent);
-       VecSubf(insetCos[2], origCos[2], cent);
-       VecSubf(insetCos[3], origCos[3], cent);
+       sub_v3_v3v3(insetCos[0], origCos[0], cent);
+       sub_v3_v3v3(insetCos[1], origCos[1], cent);
+       sub_v3_v3v3(insetCos[2], origCos[2], cent);
+       sub_v3_v3v3(insetCos[3], origCos[3], cent);
        
-       VecMulf(insetCos[0], inset);
-       VecMulf(insetCos[1], inset);
-       VecMulf(insetCos[2], inset);
-       VecMulf(insetCos[3], inset);
+       mul_v3_fl(insetCos[0], inset);
+       mul_v3_fl(insetCos[1], inset);
+       mul_v3_fl(insetCos[2], inset);
+       mul_v3_fl(insetCos[3], inset);
        
-       VecAddf(insetCos[0], insetCos[0], cent);
-       VecAddf(insetCos[1], insetCos[1], cent);
-       VecAddf(insetCos[2], insetCos[2], cent);
-       VecAddf(insetCos[3], insetCos[3], cent);
+       add_v3_v3(insetCos[0], cent);
+       add_v3_v3(insetCos[1], cent);
+       add_v3_v3(insetCos[2], cent);
+       add_v3_v3(insetCos[3], cent);
 }
 
 
@@ -1792,17 +1652,17 @@ static void scale_tri(float insetCos[4][3], float *origCos[4], const float inset
        cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1]) / 3.0f;
        cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2]) / 3.0f;
        
-       VecSubf(insetCos[0], origCos[0], cent);
-       VecSubf(insetCos[1], origCos[1], cent);
-       VecSubf(insetCos[2], origCos[2], cent);
+       sub_v3_v3v3(insetCos[0], origCos[0], cent);
+       sub_v3_v3v3(insetCos[1], origCos[1], cent);
+       sub_v3_v3v3(insetCos[2], origCos[2], cent);
        
-       VecMulf(insetCos[0], inset);
-       VecMulf(insetCos[1], inset);
-       VecMulf(insetCos[2], inset);
+       mul_v3_fl(insetCos[0], inset);
+       mul_v3_fl(insetCos[1], inset);
+       mul_v3_fl(insetCos[2], inset);
        
-       VecAddf(insetCos[0], insetCos[0], cent);
-       VecAddf(insetCos[1], insetCos[1], cent);
-       VecAddf(insetCos[2], insetCos[2], cent);
+       add_v3_v3(insetCos[0], cent);
+       add_v3_v3(insetCos[1], cent);
+       add_v3_v3(insetCos[2], cent);
 }
 
 
@@ -1827,10 +1687,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
         * 
@@ -1889,26 +1749,26 @@ static void rect_to_uvspace_ortho(
        /* get the UV space bounding box */
        uv[0] = bucket_bounds->xmax;
        uv[1] = bucket_bounds->ymin;
-       BarycentricWeights2f(uv, v1coSS, v2coSS, v3coSS, w);
-       Vec2Lerp3f(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w);
+       barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
+       interp_v2_v2v2v2(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w);
 
        //uv[0] = bucket_bounds->xmax; // set above
        uv[1] = bucket_bounds->ymax;
-       BarycentricWeights2f(uv, v1coSS, v2coSS, v3coSS, w);
-       Vec2Lerp3f(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w);
+       barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
+       interp_v2_v2v2v2(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w);
 
        uv[0] = bucket_bounds->xmin;
        //uv[1] = bucket_bounds->ymax; // set above
-       BarycentricWeights2f(uv, v1coSS, v2coSS, v3coSS, w);
-       Vec2Lerp3f(bucket_bounds_uv[flip?1:2], uv1co, uv2co, uv3co, w);
+       barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
+       interp_v2_v2v2v2(bucket_bounds_uv[flip?1:2], uv1co, uv2co, uv3co, w);
 
        //uv[0] = bucket_bounds->xmin; // set above
        uv[1] = bucket_bounds->ymin;
-       BarycentricWeights2f(uv, v1coSS, v2coSS, v3coSS, w);
-       Vec2Lerp3f(bucket_bounds_uv[flip?0:3], uv1co, uv2co, uv3co, w);
+       barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
+       interp_v2_v2v2v2(bucket_bounds_uv[flip?0:3], uv1co, uv2co, uv3co, w);
 }
 
-/* same as above but use BarycentricWeightsPersp2f */
+/* same as above but use barycentric_weights_v2_persp */
 static void rect_to_uvspace_persp(
                rctf *bucket_bounds,
                float *v1coSS, float *v2coSS, float *v3coSS,
@@ -1923,23 +1783,23 @@ static void rect_to_uvspace_persp(
        /* get the UV space bounding box */
        uv[0] = bucket_bounds->xmax;
        uv[1] = bucket_bounds->ymin;
-       BarycentricWeightsPersp2f(uv, v1coSS, v2coSS, v3coSS, w);
-       Vec2Lerp3f(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w);
+       barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
+       interp_v2_v2v2v2(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w);
 
        //uv[0] = bucket_bounds->xmax; // set above
        uv[1] = bucket_bounds->ymax;
-       BarycentricWeightsPersp2f(uv, v1coSS, v2coSS, v3coSS, w);
-       Vec2Lerp3f(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w);
+       barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
+       interp_v2_v2v2v2(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w);
 
        uv[0] = bucket_bounds->xmin;
        //uv[1] = bucket_bounds->ymax; // set above
-       BarycentricWeightsPersp2f(uv, v1coSS, v2coSS, v3coSS, w);
-       Vec2Lerp3f(bucket_bounds_uv[flip?1:2], uv1co, uv2co, uv3co, w);
+       barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
+       interp_v2_v2v2v2(bucket_bounds_uv[flip?1:2], uv1co, uv2co, uv3co, w);
 
        //uv[0] = bucket_bounds->xmin; // set above
        uv[1] = bucket_bounds->ymin;
-       BarycentricWeightsPersp2f(uv, v1coSS, v2coSS, v3coSS, w);
-       Vec2Lerp3f(bucket_bounds_uv[flip?0:3], uv1co, uv2co, uv3co, w);
+       barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
+       interp_v2_v2v2v2(bucket_bounds_uv[flip?0:3], uv1co, uv2co, uv3co, w);
 }
 
 /* This works as we need it to but we can save a few steps and not use it */
@@ -1966,7 +1826,7 @@ static float angle_2d_clockwise(const float p1[2], const float p2[2], const floa
 /* limit must be a fraction over 1.0f */
 static int IsectPT2Df_limit(float pt[2], float v1[2], float v2[2], float v3[2], float limit)
 {
-       return ((AreaF2Dfl(pt,v1,v2) + AreaF2Dfl(pt,v2,v3) + AreaF2Dfl(pt,v3,v1)) / (AreaF2Dfl(v1,v2,v3))) < limit;
+       return ((area_tri_v2(pt,v1,v2) + area_tri_v2(pt,v2,v3) + area_tri_v2(pt,v3,v1)) / (area_tri_v2(v1,v2,v3))) < limit;
 }
 
 /* Clip the face by a bucket and set the uv-space bucket_bounds_uv
@@ -1990,7 +1850,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];
 
@@ -2182,14 +2042,14 @@ static void project_bucket_clip_face(
                
                if (is_ortho) {
                        for(i=0; i<(*tot); i++) {
-                               BarycentricWeights2f(isectVCosSS[i], v1coSS, v2coSS, v3coSS, w);
-                               Vec2Lerp3f(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
+                               barycentric_weights_v2(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
+                               interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
                        }
                }
                else {
                        for(i=0; i<(*tot); i++) {
-                               BarycentricWeightsPersp2f(isectVCosSS[i], v1coSS, v2coSS, v3coSS, w);
-                               Vec2Lerp3f(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
+                               barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
+                               interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
                        }
                }
        }
@@ -2272,15 +2132,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;
                
        }
@@ -2290,10 +2150,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;
                
        }
@@ -2344,6 +2204,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
        int uv_clip_tot;
        const short is_ortho = ps->is_ortho;
        const short do_backfacecull = ps->do_backfacecull;
+       const short do_clip= ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
        
        vCo[0] = ps->dm_mvert[mf->v1].co;
        vCo[1] = ps->dm_mvert[mf->v2].co;
@@ -2443,10 +2304,9 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
                                                else                    screen_px_from_persp(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
                                                
                                                /* a pitty we need to get the worldspace pixel location here */
-                                               if(ps->rv3d->rflag & RV3D_CLIPPING) {
-                                                       VecLerp3f(wco, ps->dm_mvert[ (*(&mf->v1 + i1)) ].co, ps->dm_mvert[ (*(&mf->v1 + i2)) ].co, ps->dm_mvert[ (*(&mf->v1 + i3)) ].co, w);
-                                                       Mat4MulVecfl(ps->ob->obmat, wco);
-                                                       if(view3d_test_clipping(ps->rv3d, wco)) {
+                                               if(do_clip) {
+                                                       interp_v3_v3v3v3(wco, ps->dm_mvert[ (*(&mf->v1 + i1)) ].co, ps->dm_mvert[ (*(&mf->v1 + i2)) ].co, ps->dm_mvert[ (*(&mf->v1 + i3)) ].co, w);
+                                                       if(view3d_test_clipping(ps->rv3d, wco, 1)) {
                                                                continue; /* Watch out that no code below this needs to run */
                                                        }
                                                }
@@ -2566,7 +2426,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
                                                line_clip_rect2f(bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1])
                                ) {
 
-                                       ftot = Vec2Lenf(vCoSS[fidx1], vCoSS[fidx2]); /* screenspace edge length */
+                                       ftot = len_v2v2(vCoSS[fidx1], vCoSS[fidx2]); /* screenspace edge length */
                                        
                                        if (ftot > 0.0f) { /* avoid div by zero */
                                                if (mf->v4) {
@@ -2574,19 +2434,19 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
                                                        else                                            side= 0;
                                                }
                                                
-                                               fac1 = Vec2Lenf(vCoSS[fidx1], bucket_clip_edges[0]) / ftot;
-                                               fac2 = Vec2Lenf(vCoSS[fidx1], bucket_clip_edges[1]) / ftot;
+                                               fac1 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[0]) / ftot;
+                                               fac2 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[1]) / ftot;
                                                
-                                               Vec2Lerpf(seam_subsection[0], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac1);
-                                               Vec2Lerpf(seam_subsection[1], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac2);
+                                               interp_v2_v2v2(seam_subsection[0], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac1);
+                                               interp_v2_v2v2(seam_subsection[1], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac2);
 
-                                               Vec2Lerpf(seam_subsection[2], outset_uv[fidx1], outset_uv[fidx2], fac2);
-                                               Vec2Lerpf(seam_subsection[3], outset_uv[fidx1], outset_uv[fidx2], fac1);
+                                               interp_v2_v2v2(seam_subsection[2], outset_uv[fidx1], outset_uv[fidx2], fac2);
+                                               interp_v2_v2v2(seam_subsection[3], outset_uv[fidx1], outset_uv[fidx2], fac1);
                                                
                                                /* if the bucket_clip_edges values Z values was kept we could avoid this
                                                 * Inset needs to be added so occlusion tests wont hit adjacent faces */
-                                               VecLerpf(edge_verts_inset_clip[0], insetCos[fidx1], insetCos[fidx2], fac1);
-                                               VecLerpf(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2);
+                                               interp_v3_v3v3(edge_verts_inset_clip[0], insetCos[fidx1], insetCos[fidx2], fac1);
+                                               interp_v3_v3v3(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2);
                                                
 
                                                if (pixel_bounds_uv(seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3], &bounds_px, ibuf->x, ibuf->y, 1)) {
@@ -2603,7 +2463,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
                                                                        uv[0] = (float)x / ibuf_xf; /* use offset uvs instead */
                                                                        
                                                                        /* test we're inside uvspace bucket and triangle bounds */
-                                                                       if (IsectPQ2Df(uv, seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3])) {
+                                                                       if (isect_point_quad_v2(uv, seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3])) {
                                                                                
                                                                                /* We need to find the closest point along the face edge,
                                                                                 * getting the screen_px_from_*** wont work because our actual location
@@ -2620,13 +2480,13 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
                                                                                fac = lambda_cp_line2(uv, seam_subsection[0], seam_subsection[1]);
                                                                                if (fac < 0.0f)         { VECCOPY(pixelScreenCo, edge_verts_inset_clip[0]); }
                                                                                else if (fac > 1.0f)    { VECCOPY(pixelScreenCo, edge_verts_inset_clip[1]); }
-                                                                               else                            { VecLerpf(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac); }
+                                                                               else                            { interp_v3_v3v3(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac); }
                                                                                
                                                                                if (!is_ortho) {
                                                                                        pixelScreenCo[3] = 1.0f;
-                                                                                       Mat4MulVec4fl((float(*)[4])ps->projectMat, pixelScreenCo); /* cast because of const */
-                                                                                       pixelScreenCo[0] = (float)(ps->ar->winx/2.0f)+(ps->ar->winx/2.0f)*pixelScreenCo[0]/pixelScreenCo[3];    
-                                                                                       pixelScreenCo[1] = (float)(ps->ar->winy/2.0f)+(ps->ar->winy/2.0f)*pixelScreenCo[1]/pixelScreenCo[3];
+                                                                                       mul_m4_v4((float(*)[4])ps->projectMat, pixelScreenCo); /* cast because of const */
+                                                                                       pixelScreenCo[0] = (float)(ps->winx/2.0f)+(ps->winx/2.0f)*pixelScreenCo[0]/pixelScreenCo[3];
+                                                                                       pixelScreenCo[1] = (float)(ps->winy/2.0f)+(ps->winy/2.0f)*pixelScreenCo[1]/pixelScreenCo[3];
                                                                                        pixelScreenCo[2] = pixelScreenCo[2]/pixelScreenCo[3]; /* Use the depth for bucket point occlusion */
                                                                                }
                                                                                
@@ -2637,10 +2497,10 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
 #if 0
                                                                                                /* This is not QUITE correct since UV is not inside the UV's but good enough for seams */
                                                                                                if (side) {
-                                                                                                       BarycentricWeights2f(uv, tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], w);
+                                                                                                       barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], uv, w);
                                                                                                }
                                                                                                else {
-                                                                                                       BarycentricWeights2f(uv, tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], w);
+                                                                                                       barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], uv, w);
                                                                                                }
 #endif
 #if 1
@@ -2649,22 +2509,21 @@ 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
                                                                                        }
                                                                                        
                                                                                        /* a pitty we need to get the worldspace pixel location here */
-                                                                                       if(ps->rv3d->rflag & RV3D_CLIPPING) {
-                                                                                               if (side)       VecLerp3f(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
-                                                                                               else            VecLerp3f(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
-                                                                                               
-                                                                                               Mat4MulVecfl(ps->ob->obmat, wco);
-                                                                                               if(view3d_test_clipping(ps->rv3d, wco)) {
+                                                                                       if(do_clip) {
+                                                                                               if (side)       interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
+                                                                                               else            interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
+
+                                                                                               if(view3d_test_clipping(ps->rv3d, wco, 1)) {
                                                                                                        continue; /* Watch out that no code below this needs to run */
                                                                                                }
                                                                                        }
@@ -2708,11 +2567,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);
@@ -2790,7 +2650,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;
@@ -2823,23 +2683,23 @@ static int project_bucket_face_isect(ProjPaintState *ps, float min[2], float max
        p4[0] = bucket_bounds.xmax;     p4[1] = bucket_bounds.ymin;
                
        if (mf->v4) {
-               if(     IsectPQ2Df(p1, v1, v2, v3, v4) || IsectPQ2Df(p2, v1, v2, v3, v4) || IsectPQ2Df(p3, v1, v2, v3, v4) || IsectPQ2Df(p4, v1, v2, v3, v4) ||
+               if(     isect_point_quad_v2(p1, v1, v2, v3, v4) || isect_point_quad_v2(p2, v1, v2, v3, v4) || isect_point_quad_v2(p3, v1, v2, v3, v4) || isect_point_quad_v2(p4, v1, v2, v3, v4) ||
                        /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
-                       (IsectLL2Df(p1, p2, v1, v2) || IsectLL2Df(p1, p2, v2, v3) || IsectLL2Df(p1, p2, v3, v4)) ||
-                       (IsectLL2Df(p2, p3, v1, v2) || IsectLL2Df(p2, p3, v2, v3) || IsectLL2Df(p2, p3, v3, v4)) ||
-                       (IsectLL2Df(p3, p4, v1, v2) || IsectLL2Df(p3, p4, v2, v3) || IsectLL2Df(p3, p4, v3, v4)) ||
-                       (IsectLL2Df(p4, p1, v1, v2) || IsectLL2Df(p4, p1, v2, v3) || IsectLL2Df(p4, p1, v3, v4))
+                       (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3) || isect_line_line_v2(p1, p2, v3, v4)) ||
+                       (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3) || isect_line_line_v2(p2, p3, v3, v4)) ||
+                       (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3) || isect_line_line_v2(p3, p4, v3, v4)) ||
+                       (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3) || isect_line_line_v2(p4, p1, v3, v4))
                ) {
                        return 1;
                }
        }
        else {
-               if(     IsectPT2Df(p1, v1, v2, v3) || IsectPT2Df(p2, v1, v2, v3) || IsectPT2Df(p3, v1, v2, v3) || IsectPT2Df(p4, v1, v2, v3) ||
+               if(     isect_point_tri_v2(p1, v1, v2, v3) || isect_point_tri_v2(p2, v1, v2, v3) || isect_point_tri_v2(p3, v1, v2, v3) || isect_point_tri_v2(p4, v1, v2, v3) ||
                        /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
-                       (IsectLL2Df(p1, p2, v1, v2) || IsectLL2Df(p1, p2, v2, v3)) ||
-                       (IsectLL2Df(p2, p3, v1, v2) || IsectLL2Df(p2, p3, v2, v3)) ||
-                       (IsectLL2Df(p3, p4, v1, v2) || IsectLL2Df(p3, p4, v2, v3)) ||
-                       (IsectLL2Df(p4, p1, v1, v2) || IsectLL2Df(p4, p1, v2, v3))
+                       (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3)) ||
+                       (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3)) ||
+                       (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3)) ||
+                       (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3))
                ) {
                        return 1;
                }
@@ -2850,11 +2710,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 */
        
@@ -2871,10 +2731,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 */
@@ -2905,6 +2763,19 @@ static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf,
 #endif
 }
 
+static int project_paint_view_clip(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
+{
+       int orth= get_view3d_cliprange(v3d, rv3d, clipsta, clipend);
+
+       if (orth) { /* only needed for ortho */
+               float fac = 2.0f / ((*clipend) - (*clipsta));
+               *clipsta *= fac;
+               *clipend *= fac;
+       }
+
+       return orth;
+}
+
 /* run once per stroke before projection painting */
 static void project_paint_begin(ProjPaintState *ps)
 {      
@@ -2913,8 +2784,9 @@ static void project_paint_begin(ProjPaintState *ps)
        
        float no[3];
        
-       float (*projScreenCo)[4]; /* Note, we could have 4D vectors are only needed for */
+       float *projScreenCo; /* Note, we could have 4D vectors are only needed for */
        float projMargin;
+
        /* Image Vars - keep track of images we have used */
        LinkNode *image_LinkList = NULL;
        LinkNode *node;
@@ -2928,18 +2800,43 @@ static void project_paint_begin(ProjPaintState *ps)
        
        int a, i; /* generic looping vars */
        int image_index = -1, face_index;
+       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 ---- */
        
+       if(ps->source==PROJ_SRC_VIEW)
+               ED_view3d_local_clipping(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */
+
        /* paint onto the derived mesh */
-       ps->dm = mesh_get_derived_final(ps->scene, ps->ob, ps->v3d->customdata_mask);
+       
+       /* Workaround for subsurf selection, try the display mesh first */
+       if (ps->source==PROJ_SRC_IMAGE_CAM) {
+               /* using render mesh, assume only camera was rendered from */
+               ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->v3d->customdata_mask | CD_MASK_MTFACE);
+               ps->dm_release= TRUE;
+       }
+       else if(ps->ob->derivedFinal && CustomData_has_layer( &ps->ob->derivedFinal->faceData, CD_MTFACE)) {
+               ps->dm = ps->ob->derivedFinal;
+               ps->dm_release= FALSE;
+       }
+       else {
+               ps->dm = mesh_get_derived_final(ps->scene, ps->ob, ps->v3d->customdata_mask | CD_MASK_MTFACE);
+               ps->dm_release= TRUE;
+       }
        
        if ( !CustomData_has_layer( &ps->dm->faceData, CD_MTFACE) ) {
+               
+               if(ps->dm_release)
+                       ps->dm->release(ps->dm);
+               
                ps->dm = NULL;
                return; 
        }
+       
        ps->dm_mvert = ps->dm->getVertArray(ps->dm);
        ps->dm_mface = ps->dm->getFaceArray(ps->dm);
        ps->dm_mtface= ps->dm->getFaceDataArray(ps->dm, CD_MTFACE);
@@ -2961,104 +2858,158 @@ static void project_paint_begin(ProjPaintState *ps)
                if (ps->dm_mtface_clone==NULL || ps->dm_mtface_clone==ps->dm_mtface) {
                        ps->do_layer_clone = 0;
                        ps->dm_mtface_clone= NULL;
+                       printf("ACK!\n");
                }
        }
        
-       if (ps->do_layer_mask) {
-               //int layer_num = CustomData_get_mask_layer(&ps->dm->faceData, CD_MTFACE);
-               int layer_num = CustomData_get_mask_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE);
+       if (ps->do_layer_stencil) {
+               //int layer_num = CustomData_get_stencil_layer(&ps->dm->faceData, CD_MTFACE);
+               int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE);
                if (layer_num != -1)
-                       ps->dm_mtface_mask = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
+                       ps->dm_mtface_stencil = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
                
-               if (ps->dm_mtface_mask==NULL || ps->dm_mtface_mask==ps->dm_mtface) {
-                       ps->do_layer_mask = 0;
-                       ps->dm_mtface_mask = NULL;
+               if (ps->dm_mtface_stencil==NULL || ps->dm_mtface_stencil==ps->dm_mtface) {
+                       ps->do_layer_stencil = 0;
+                       ps->dm_mtface_stencil = NULL;
                }
        }
        
-
+       /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
+       if(ps->dm->type != DM_TYPE_CDDM) {
+               ps->dm_mvert= MEM_dupallocN(ps->dm_mvert);
+               ps->dm_mface= MEM_dupallocN(ps->dm_mface);
+               /* looks like these are ok for now.*/
+               /*
+               ps->dm_mtface= MEM_dupallocN(ps->dm_mtface);
+               ps->dm_mtface_clone= MEM_dupallocN(ps->dm_mtface_clone);
+               ps->dm_mtface_stencil= MEM_dupallocN(ps->dm_mtface_stencil);
+                */
+       }
        
        ps->viewDir[0] = 0.0f;
        ps->viewDir[1] = 0.0f;
        ps->viewDir[2] = 1.0f;
        
-       view3d_get_object_project_mat(ps->rv3d, ps->ob, ps->projectMat);
-       
-       /* viewDir - object relative */
-       Mat4Invert(ps->ob->imat, ps->ob->obmat);
-       Mat3CpyMat4(mat, ps->rv3d->viewinv);
-       Mat3MulVecfl(mat, ps->viewDir);
-       Mat3CpyMat4(mat, ps->ob->imat);
-       Mat3MulVecfl(mat, ps->viewDir);
-       Normalize(ps->viewDir);
-       
-       /* viewPos - object relative */
-       VECCOPY(ps->viewPos, ps->rv3d->viewinv[3]);
-       Mat3CpyMat4(mat, ps->ob->imat);
-       Mat3MulVecfl(mat, ps->viewPos);
-       VecAddf(ps->viewPos, ps->viewPos, ps->ob->imat[3]);
-       
-       {       /* only use these for running 'get_view3d_viewplane' */
-               rctf viewplane;
-               
-               ps->is_ortho = get_view3d_viewplane(ps->v3d, ps->rv3d, ps->ar->winx, ps->ar->winy, &viewplane, &ps->clipsta, &ps->clipend, NULL);
-               
-               //printf("%f %f\n", ps->clipsta, ps->clipend);
-               if (ps->is_ortho) { /* only needed for ortho */
-                       float fac = 2.0f / (ps->clipend - ps->clipsta);  
-                       ps->clipsta *= fac;
-                       ps->clipend *= fac;
+       {
+               float viewmat[4][4];
+               float viewinv[4][4];
+
+               invert_m4_m4(ps->ob->imat, ps->ob->obmat);
+
+               if(ps->source==PROJ_SRC_VIEW) {
+                       /* normal drawing */
+                       ps->winx= ps->ar->winx;
+                       ps->winy= ps->ar->winy;
+
+                       copy_m4_m4(viewmat, ps->rv3d->viewmat);
+                       copy_m4_m4(viewinv, ps->rv3d->viewinv);
+
+                       view3d_get_object_project_mat(ps->rv3d, ps->ob, ps->projectMat);
+
+                       ps->is_ortho= project_paint_view_clip(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend);
                }
                else {
-                       /* TODO - can we even adjust for clip start/end? */
+                       /* reprojection */
+                       float winmat[4][4];
+                       float vmat[4][4];
+
+                       ps->winx= ps->reproject_ibuf->x;
+                       ps->winy= ps->reproject_ibuf->y;
+
+                       if (ps->source==PROJ_SRC_IMAGE_VIEW) {
+                               /* image stores camera data, tricky */
+                               IDProperty *idgroup= IDP_GetProperties(&ps->reproject_image->id, 0);
+                               IDProperty *view_data= IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID);
+
+                               float *array= (float *)IDP_Array(view_data);
+
+                               /* use image array, written when creating image */
+                               memcpy(winmat, array, sizeof(winmat)); array += sizeof(winmat)/sizeof(float);
+                               memcpy(viewmat, array, sizeof(viewmat)); array += sizeof(viewmat)/sizeof(float);
+                               ps->clipsta= array[0];
+                               ps->clipend= array[1];
+                               ps->is_ortho= array[2] ? 1:0;
+
+                               invert_m4_m4(viewinv, viewmat);
+                       }
+                       else if (ps->source==PROJ_SRC_IMAGE_CAM) {
+                               Object *camera= ps->scene->camera;
+
+                               /* dont actually use these */
+                               float _viewdx, _viewdy, _ycor, _lens=0.0f;
+                               rctf _viewplane;
+
+                               /* viewmat & viewinv */
+                               copy_m4_m4(viewinv, ps->scene->camera->obmat);
+                               normalize_m4(viewinv);
+                               invert_m4_m4(viewmat, viewinv);
+
+                               /* camera winmat */
+                               object_camera_matrix(&ps->scene->r, camera, ps->winx, ps->winy, 0,
+                                               winmat, &_viewplane, &ps->clipsta, &ps->clipend,
+                                               &_lens, &_ycor, &_viewdx, &_viewdy);
+
+                               ps->is_ortho= (ps->scene->r.mode & R_ORTHO) ? 1 : 0;
+                       }
+
+                       /* same as view3d_get_object_project_mat */
+                       mul_m4_m4m4(vmat, ps->ob->obmat, viewmat);
+                       mul_m4_m4m4(ps->projectMat, vmat, winmat);
                }
+
+
+               /* viewDir - object relative */
+               invert_m4_m4(ps->ob->imat, ps->ob->obmat);
+               copy_m3_m4(mat, viewinv);
+               mul_m3_v3(mat, ps->viewDir);
+               copy_m3_m4(mat, ps->ob->imat);
+               mul_m3_v3(mat, ps->viewDir);
+               normalize_v3(ps->viewDir);
                
+               /* viewPos - object relative */
+               VECCOPY(ps->viewPos, viewinv[3]);
+               copy_m3_m4(mat, ps->ob->imat);
+               mul_m3_v3(mat, ps->viewPos);
+               add_v3_v3(ps->viewPos, ps->ob->imat[3]);
        }
        
-       ps->is_airbrush = (ps->brush->flag & BRUSH_AIRBRUSH) ? 1 : 0;
-       
-       ps->is_texbrush = (ps->brush->mtex[ps->brush->texact] && ps->brush->mtex[ps->brush->texact]->tex) ? 1 : 0;
-
-       
        /* calculate vert screen coords
         * run this early so we can calculate the x/y resolution of our bucket rect */
        INIT_MINMAX2(ps->screenMin, ps->screenMax);
        
        ps->screenCoords = MEM_mallocN(sizeof(float) * ps->dm_totvert * 4, "ProjectPaint ScreenVerts");
-       projScreenCo = ps->screenCoords;
+       projScreenCo= *ps->screenCoords;
        
        if (ps->is_ortho) {
-               for(a=0; a < ps->dm_totvert; a++, projScreenCo++) {
-                       VECCOPY((*projScreenCo), ps->dm_mvert[a].co);
-                       Mat4MulVecfl(ps->projectMat, (*projScreenCo));
+               for(a=0, mv=ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScreenCo+=4) {
+                       mul_v3_m4v3(projScreenCo, ps->projectMat, mv->co);
                        
                        /* screen space, not clamped */
-                       (*projScreenCo)[0] = (float)(ps->ar->winx/2.0f)+(ps->ar->winx/2.0f)*(*projScreenCo)[0];
-                       (*projScreenCo)[1] = (float)(ps->ar->winy/2.0f)+(ps->ar->winy/2.0f)*(*projScreenCo)[1];
-                       DO_MINMAX2((*projScreenCo), ps->screenMin, ps->screenMax);
+                       projScreenCo[0] = (float)(ps->winx/2.0f)+(ps->winx/2.0f)*projScreenCo[0];
+                       projScreenCo[1] = (float)(ps->winy/2.0f)+(ps->winy/2.0f)*projScreenCo[1];
+                       DO_MINMAX2(projScreenCo, ps->screenMin, ps->screenMax);
                }
        }
        else {
-               for(a=0; a < ps->dm_totvert; a++, projScreenCo++) {
-                       VECCOPY((*projScreenCo), ps->dm_mvert[a].co);
-                       (*projScreenCo)[3] = 1.0f;
+               for(a=0, mv=ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScreenCo+=4) {
+                       copy_v3_v3(projScreenCo, mv->co);
+                       projScreenCo[3] = 1.0f;
 
-                       Mat4MulVec4fl(ps->projectMat, (*projScreenCo));
+                       mul_m4_v4(ps->projectMat, projScreenCo);
 
-                       
-                       if ((*projScreenCo)[3] > ps->clipsta) {
+                       if (projScreenCo[3] > ps->clipsta) {
                                /* screen space, not clamped */
-                               (*projScreenCo)[0] = (float)(ps->ar->winx/2.0f)+(ps->ar->winx/2.0f)*(*projScreenCo)[0]/(*projScreenCo)[3];
-                               (*projScreenCo)[1] = (float)(ps->ar->winy/2.0f)+(ps->ar->winy/2.0f)*(*projScreenCo)[1]/(*projScreenCo)[3];
-                               (*projScreenCo)[2] = (*projScreenCo)[2]/(*projScreenCo)[3]; /* Use the depth for bucket point occlusion */
-                               DO_MINMAX2((*projScreenCo), ps->screenMin, ps->screenMax);
+                               projScreenCo[0] = (float)(ps->winx/2.0f)+(ps->winx/2.0f)*projScreenCo[0]/projScreenCo[3];
+                               projScreenCo[1] = (float)(ps->winy/2.0f)+(ps->winy/2.0f)*projScreenCo[1]/projScreenCo[3];
+                               projScreenCo[2] = projScreenCo[2]/projScreenCo[3]; /* Use the depth for bucket point occlusion */
+                               DO_MINMAX2(projScreenCo, ps->screenMin, ps->screenMax);
                        }
                        else {
                                /* TODO - deal with cases where 1 side of a face goes behind the view ?
                                 * 
                                 * After some research this is actually very tricky, only option is to
                                 * clip the derived mesh before painting, which is a Pain */
-                               (*projScreenCo)[0] = FLT_MAX;
+                               projScreenCo[0] = FLT_MAX;
                        }
                }
        }
@@ -3073,20 +3024,29 @@ static void project_paint_begin(ProjPaintState *ps)
        ps->screenMax[1] += projMargin;
        ps->screenMin[1] -= projMargin;
        
+       if(ps->source==PROJ_SRC_VIEW) {
 #ifdef PROJ_DEBUG_WINCLIP
-       CLAMP(ps->screenMin[0], -ps->brush->size, ps->ar->winx + ps->brush->size);
-       CLAMP(ps->screenMax[0], -ps->brush->size, ps->ar->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->ar->winy + ps->brush->size);
-       CLAMP(ps->screenMax[1], -ps->brush->size, ps->ar->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]= (float)(ps->winx);
+
+               ps->screenMin[1]= 0;
+               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); */
        
@@ -3120,31 +3080,28 @@ static void project_paint_begin(ProjPaintState *ps)
                ps->thread_tot = BLI_system_thread_count();
        }
        for (a=0; a<ps->thread_tot; a++) {
-               ps->arena_mt[a] = BLI_memarena_new(1<<16);
+               ps->arena_mt[a] = BLI_memarena_new(1<<16, "project paint arena");
        }
        
        arena = ps->arena_mt[0]; 
        
        if (ps->do_backfacecull && ps->do_mask_normal) {
-               MVert *v = ps->dm_mvert;
                float viewDirPersp[3];
                
                ps->vertFlags = MEM_callocN(sizeof(char) * ps->dm_totvert, "paint-vertFlags");
                
-               for(a=0; a < ps->dm_totvert; a++, v++) {
-                       no[0] = (float)(v->no[0] / 32767.0f);
-                       no[1] = (float)(v->no[1] / 32767.0f);
-                       no[2] = (float)(v->no[2] / 32767.0f);
+               for(a=0, mv=ps->dm_mvert; a < ps->dm_totvert; a++, mv++) {
+                       normal_short_to_float_v3(no, mv->no);
                        
                        if (ps->is_ortho) {
-                               if (NormalizedVecAngle2(ps->viewDir, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
+                               if (angle_normalized_v3v3(ps->viewDir, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
                                        ps->vertFlags[a] |= PROJ_VERT_CULL;
                                }
                        }
                        else {
-                               VecSubf(viewDirPersp, ps->viewPos, v->co);
-                               Normalize(viewDirPersp);
-                               if (NormalizedVecAngle2(viewDirPersp, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
+                               sub_v3_v3v3(viewDirPersp, ps->viewPos, mv->co);
+                               normalize_v3(viewDirPersp);
+                               if (angle_normalized_v3v3(viewDirPersp, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
                                        ps->vertFlags[a] |= PROJ_VERT_CULL;
                                }
                        }
@@ -3162,12 +3119,12 @@ static void project_paint_begin(ProjPaintState *ps)
                        BLI_linklist_prepend_arena(&ps->vertFaces[mf->v2], SET_INT_IN_POINTER(face_index), arena);
                        BLI_linklist_prepend_arena(&ps->vertFaces[mf->v3], SET_INT_IN_POINTER(face_index), arena);
                        if (mf->v4) {
-                               BLI_linklist_prepend_arena(&ps->vertFaces[ mf->v4 ], SET_INT_IN_POINTER(face_index), arena);
+                               BLI_linklist_prepend_arena(&ps->vertFaces[mf->v4], SET_INT_IN_POINTER(face_index), arena);
                        }
                }
 #endif
                
-               if (tf->tpage && ((G.f & G_FACESELECT)==0 || mf->flag & ME_FACE_SEL)) {
+               if (tf->tpage && ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_MASK)==0 || mf->flag & ME_FACE_SEL)) {
                        
                        float *v1coSS, *v2coSS, *v3coSS, *v4coSS=NULL;
                        
@@ -3233,7 +3190,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;
                                        }
                                        
@@ -3256,7 +3213,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);
                        }
                }
        }
@@ -3281,14 +3238,13 @@ static void project_paint_begin_clone(ProjPaintState *ps, int mouse[2])
        /* setup clone offset */
        if (ps->tool == PAINT_TOOL_CLONE) {
                float projCo[4];
-               float *curs= give_cursor(ps->scene, ps->v3d);
-               VECCOPY(projCo, curs);
-               Mat4MulVecfl(ps->ob->imat, projCo);
+               copy_v3_v3(projCo, give_cursor(ps->scene, ps->v3d));
+               mul_m4_v3(ps->ob->imat, projCo);
                
                projCo[3] = 1.0f;
-               Mat4MulVec4fl(ps->projectMat, projCo);
-               ps->cloneOffset[0] = mouse[0] - ((float)(ps->ar->winx/2.0f)+(ps->ar->winx/2.0f)*projCo[0]/projCo[3]);
-               ps->cloneOffset[1] = mouse[1] - ((float)(ps->ar->winy/2.0f)+(ps->ar->winy/2.0f)*projCo[1]/projCo[3]);
+               mul_m4_v4(ps->projectMat, projCo);
+               ps->cloneOffset[0] = mouse[0] - ((float)(ps->winx/2.0f)+(ps->winx/2.0f)*projCo[0]/projCo[3]);
+               ps->cloneOffset[1] = mouse[1] - ((float)(ps->winy/2.0f)+(ps->winy/2.0f)*projCo[1]/projCo[3]);
        }       
 }      
 
@@ -3301,7 +3257,7 @@ static void project_paint_end(ProjPaintState *ps)
                ProjPixel *projPixel;
                ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL;
                LinkNode *pixel_node;
-               UndoTile *tile;
+               void *tilerect;
                MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for non threaded case */
                                
                int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could get an X/Y but easier to loop through all possible buckets */
@@ -3317,8 +3273,8 @@ static void project_paint_end(ProjPaintState *ps)
                int last_tile_width=0;
                
                for(a=0, last_projIma=ps->projImages; a < ps->image_tot; a++, last_projIma++) {
-                       int size = sizeof(UndoTile **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y);
-                       last_projIma->undoRect = (UndoTile **) BLI_memarena_alloc(arena, size);
+                       int size = sizeof(void **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y);
+                       last_projIma->undoRect = (void **) BLI_memarena_alloc(arena, size);
                        memset(last_projIma->undoRect, 0, size);
                        last_projIma->ibuf->userflags |= IB_BITMAPDIRTY;
                }
@@ -3358,21 +3314,21 @@ static void project_paint_end(ProjPaintState *ps)
                                        
                                        if (last_projIma->undoRect[tile_index]==NULL) {
                                                /* add the undo tile from the modified image, then write the original colors back into it */
-                                               tile = last_projIma->undoRect[tile_index] = undo_init_tile(&last_projIma->ima->id, last_projIma->ibuf, is_float ? (&tmpibuf_float):(&tmpibuf) , x_tile, y_tile);
+                                               tilerect = last_projIma->undoRect[tile_index] = image_undo_push_tile(last_projIma->ima, last_projIma->ibuf, is_float ? (&tmpibuf_float):(&tmpibuf) , x_tile, y_tile);
                                        }
                                        else {
-                                               tile = last_projIma->undoRect[tile_index];
+                                               tilerect = last_projIma->undoRect[tile_index];
                                        }
                                        
                                        /* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color
                                         * because allocating the tiles allong the way slows down painting */
                                        
                                        if (is_float) {
-                                               float *rgba_fp = (float *)tile->rect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4;
+                                               float *rgba_fp = (float *)tilerect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4;
                                                QUATCOPY(rgba_fp, projPixel->origColor.f);
                                        }
                                        else {
-                                               ((unsigned int *)tile->rect)[ (projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE ] = projPixel->origColor.uint;
+                                               ((unsigned int *)tilerect)[ (projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE ] = projPixel->origColor.uint;
                                        }
                                }
                        }
@@ -3402,7 +3358,20 @@ static void project_paint_end(ProjPaintState *ps)
                BLI_memarena_free(ps->arena_mt[a]);
        }
        
-       ps->dm->release(ps->dm);
+       /* copy for subsurf/multires, so throw away */
+       if(ps->dm->type != DM_TYPE_CDDM) {
+               if(ps->dm_mvert) MEM_freeN(ps->dm_mvert);
+               if(ps->dm_mface) MEM_freeN(ps->dm_mface);
+               /* looks like these dont need copying */
+               /*
+               if(ps->dm_mtface) MEM_freeN(ps->dm_mtface);
+               if(ps->dm_mtface_clone) MEM_freeN(ps->dm_mtface_clone);
+               if(ps->dm_mtface_stencil) MEM_freeN(ps->dm_mtface_stencil);
+               */
+       }
+
+       if(ps->dm_release)
+               ps->dm->release(ps->dm);
 }
 
 /* 1= an undo, -1 is a redo. */
@@ -3473,33 +3442,48 @@ static int project_image_refresh_tagged(ProjPaintState *ps)
 /* run this per painting onto each mouse location */
 static int project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2])
 {
-       float min_brush[2], max_brush[2];
-       float size_half = ((float)ps->brush->size) * 0.5f;
-       
-       /* 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 :/
-       
-       min_brush[0] = mval_f[0] - size_half;
-       min_brush[1] = mval_f[1] - size_half;
-       
-       max_brush[0] = mval_f[0] + size_half;
-       max_brush[1] = mval_f[1] + size_half;
-       
-       /* offset to make this a valid bucket index */
-       project_paint_bucket_bounds(ps, min_brush, max_brush, ps->bucketMin, ps->bucketMax);
-       
-       /* mouse outside the model areas? */
-       if (ps->bucketMin[0]==ps->bucketMax[0] || ps->bucketMin[1]==ps->bucketMax[1]) {
-               return 0;
+       if(ps->source==PROJ_SRC_VIEW) {
+               float min_brush[2], max_brush[2];
+               const float radius = (float)brush_size(ps->brush);
+
+               /* so we dont have a bucket bounds that is way too small to paint into */
+               // if (radius < 1.0f) radius = 1.0f; // this doesn't work yet :/
+
+               min_brush[0] = mval_f[0] - radius;
+               min_brush[1] = mval_f[1] - radius;
+
+               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);
+
+               /* mouse outside the model areas? */
+               if (ps->bucketMin[0]==ps->bucketMax[0] || ps->bucketMin[1]==ps->bucketMax[1]) {
+                       return 0;
+               }
+
+               ps->context_bucket_x = ps->bucketMin[0];
+               ps->context_bucket_y = ps->bucketMin[1];
+       }
+       else { /* reproject: PROJ_SRC_* */
+               ps->bucketMin[0]= 0;
+               ps->bucketMin[1]= 0;
+
+               ps->bucketMax[0]= ps->buckets_x;
+               ps->bucketMax[1]= ps->buckets_y;
+
+               ps->context_bucket_x = 0;
+               ps->context_bucket_y = 0;
        }
-       
-       ps->context_bucket_x = ps->bucketMin[0];
-       ps->context_bucket_y = ps->bucketMin[1];
        return 1;
 }
 
+
 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);
        
@@ -3511,7 +3495,9 @@ static int project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf
                        /* use bucket_bounds for project_bucket_isect_circle and project_bucket_init*/
                        project_bucket_bounds(ps, ps->context_bucket_x, ps->context_bucket_y, bucket_bounds);
                        
-                       if (project_bucket_isect_circle(ps->context_bucket_x, ps->context_bucket_y, mval, ps->brush->size * ps->brush->size, bucket_bounds)) {
+                       if (    (ps->source != PROJ_SRC_VIEW) ||
+                                       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++;
                                
@@ -3558,14 +3544,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 do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask)
+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 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);
@@ -3576,7 +3576,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);
@@ -3593,7 +3593,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];
        
@@ -3604,7 +3604,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];
@@ -3683,7 +3683,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;
@@ -3691,27 +3690,26 @@ static void *do_projectpaint_thread(void *ph_v)
        rctf bucket_bounds;
        
        /* for smear only */
-       float pos_ofs[2];
+       float pos_ofs[2] = {0};
        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];
                
-               smearArena = BLI_memarena_new(1<<16);
+               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)) {                              
@@ -3722,91 +3720,120 @@ static void *do_projectpaint_thread(void *ph_v)
                        project_bucket_init(ps, thread_index, bucket_index, &bucket_bounds);
                }
 
-               for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
-                       
-                       projPixel = (ProjPixel *)node->link;
+               if(ps->source != PROJ_SRC_VIEW) {
+
+                       /* Re-Projection, simple, no brushes! */
                        
-                       /*dist = Vec2Lenf(projPixel->projCoSS, pos);*/ /* correct but uses a sqrtf */
-                       dist_nosqrt = Vec2Lenf_nosqrt(projPixel->projCoSS, pos);
+                       for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
+                               projPixel = (ProjPixel *)node->link;
+
+                               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_accum(projPixel->pixel.ch_pt,  projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask*projPixel->newColor.ch[3]));
+
+                               }
+                       }
+               }
+               else {
+                       /* Normal brush painting */
                        
-                       /*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 (falloff > 0.0f) {
-                                       if (ps->is_texbrush) {
-                                               brush_sample_tex(ps->brush, projPixel->projCoSS, rgba);
-                                               alpha = rgba[3];
-                                       } else {
-                                               alpha = 1.0f;
-                                       }
-                                       
-                                       if (ps->is_airbrush) {
-                                               /* for an aurbrush there is no real mask, so just multiply the alpha by it */
-                                               alpha *= falloff * ps->brush->alpha;
-                                               mask = ((float)projPixel->mask)/65535.0f;
-                                       }
-                                       else {
-                                               /* This brush dosnt accumulate so add some curve to the brushes falloff */
-                                               falloff = 1.0f - falloff;
-                                               falloff = 1.0f - (falloff * falloff);
+                       for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
+
+                               projPixel = (ProjPixel *)node->link;
+
+                               /*dist = len_v2v2(projPixel->projCoSS, pos);*/ /* correct but uses a sqrtf */
+                               dist_nosqrt = Vec2Lenf_nosqrt(projPixel->projCoSS, pos);
+
+                               /*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) {
+                                                       /* 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;
+                                               }
                                                
-                                               mask_short = projPixel->mask * (ps->brush->alpha * falloff);
-                                               if (mask_short > projPixel->mask_max) {
-                                                       mask = ((float)mask_short)/65535.0f;
-                                                       projPixel->mask_max = mask_short;
+                                               if (ps->is_airbrush) {
+                                                       /* for an aurbrush there is no real mask, so just multiply the alpha by it */
+                                                       alpha *= falloff * brush_alpha(ps->brush);
+                                                       mask = ((float)projPixel->mask)/65535.0f;
                                                }
                                                else {
-                                                       /*mask = ((float)projPixel->mask_max)/65535.0f;*/
+                                                       /* This brush dosnt accumulate so add some curve to the brushes falloff */
+                                                       falloff = 1.0f - falloff;
+                                                       falloff = 1.0f - (falloff * falloff);
                                                        
-                                                       /* Go onto the next pixel */
-                                                       continue;
+                                                       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;
+                                                       }
+                                                       else {
+                                                               /*mask = ((float)projPixel->mask_max)/65535.0f;*/
+
+                                                               /* Go onto the next pixel */
+                                                               continue;
+                                                       }
                                                }
-                                       }
-                                       
-                                       if (alpha > 0.0f) {
                                                
-                                               if (last_index != projPixel->image_index) {
-                                                       last_index = projPixel->image_index;
-                                                       last_projIma = projImages + last_index;
+                                               if (alpha > 0.0f) {
+
+                                                       if (last_index != projPixel->image_index) {
+                                                               last_index = projPixel->image_index;
+                                                               last_projIma = projImages + last_index;
+
+                                                               last_projIma->touch = 1;
+                                                               is_floatbuf = last_projIma->ibuf->rect_float ? 1 : 0;
+                                                       }
+
+                                                       last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
+                                                       last_partial_redraw_cell->x1 = MIN2(last_partial_redraw_cell->x1, projPixel->x_px);
+                                                       last_partial_redraw_cell->y1 = MIN2(last_partial_redraw_cell->y1, projPixel->y_px);
+
+                                                       last_partial_redraw_cell->x2 = MAX2(last_partial_redraw_cell->x2, projPixel->x_px+1);
+                                                       last_partial_redraw_cell->y2 = MAX2(last_partial_redraw_cell->y2, projPixel->y_px+1);
+
                                                        
-                                                       last_projIma->touch = 1;
-                                                       is_floatbuf = last_projIma->ibuf->rect_float ? 1 : 0;
-                                               }
-                                               
-                                               last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
-                                               last_partial_redraw_cell->x1 = MIN2(last_partial_redraw_cell->x1, projPixel->x_px);
-                                               last_partial_redraw_cell->y1 = MIN2(last_partial_redraw_cell->y1, projPixel->y_px);
-                                               
-                                               last_partial_redraw_cell->x2 = MAX2(last_partial_redraw_cell->x2, projPixel->x_px+1);
-                                               last_partial_redraw_cell->y2 = MAX2(last_partial_redraw_cell->y2, projPixel->y_px+1);
-                                               
-                                               
-                                               switch(tool) {
-                                               case PAINT_TOOL_CLONE:
-                                                       if (is_floatbuf) {
-                                                               if (((ProjPixelClone *)projPixel)->clonepx.f[3]) {
-                                                                       do_projectpaint_clone_f(ps, projPixel, rgba, alpha, mask);
+                                                       switch(tool) {
+                                                       case PAINT_TOOL_CLONE:
+                                                               if (is_floatbuf) {
+                                                                       if (((ProjPixelClone *)projPixel)->clonepx.f[3]) {
+                                                                               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);
+                                                               else {
+                                                                       if (((ProjPixelClone*)projPixel)->clonepx.ch[3]) {
+                                                                               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, 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);
+                                                               else                            do_projectpaint_draw(ps, projPixel, rgba, alpha, mask);
+                                                               break;
                                                        }
-                                                       break;
-                                               case PAINT_TOOL_SMEAR:
-                                                       Vec2Subf(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);
-                                                       break;
-                                               default:
-                                                       if (is_floatbuf)        do_projectpaint_draw_f(ps, projPixel, rgba, alpha, mask);
-                                                       else                            do_projectpaint_draw(ps, projPixel, rgba, alpha, mask);
-                                                       break;
                                                }
+
+                                               if(lock_alpha) {
+                                                       if (is_floatbuf)        projPixel->pixel.f_pt[3]= projPixel->origColor.f[3];
+                                                       else                            projPixel->pixel.ch_pt[3]= projPixel->origColor.ch[3];
+                                               }
+
+                                               /* done painting */
                                        }
-                                       /* done painting */
                                }
                        }
                }
@@ -3831,7 +3858,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;
@@ -3855,8 +3882,8 @@ static int project_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *po
                //memset(&handles[a], 0, sizeof(BakeShade));
                
                handles[a].ps = ps;
-               VECCOPY2D(handles[a].mval, pos);
-               VECCOPY2D(handles[a].prevmval, lastpos);
+               copy_v2_v2(handles[a].mval, pos);
+               copy_v2_v2(handles[a].prevmval, lastpos);
                
                /* thread spesific */
                handles[a].thread_index = a;
@@ -3898,14 +3925,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);
@@ -3942,7 +3969,6 @@ static void imapaint_clear_partial_redraw()
 static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
 {
        ImBuf *tmpibuf = NULL;
-       UndoTile *tile;
        int srcx= 0, srcy= 0, origx;
 
        IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
@@ -3969,17 +3995,9 @@ static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w,
        origx = (x >> IMAPAINT_TILE_BITS);
        y = (y >> IMAPAINT_TILE_BITS);
        
-       for (; y <= h; y++) {
-               for (x=origx; x <= w; x++) {
-                       for(tile=curundo->tiles.first; tile; tile=tile->next)
-                               if(tile->x == x && tile->y == y && strcmp(tile->id.name, ima->id.name)==0)
-                                       break;
-
-                       if(!tile) {
-                               undo_init_tile(&ima->id, ibuf, &tmpibuf, x, y);
-                       }
-               }
-       }
+       for (; y <= h; y++)
+               for (x=origx; x <= w; x++)
+                       image_undo_push_tile(ima, ibuf, &tmpibuf, x, y);
 
        ibuf->userflags |= IB_BITMAPDIRTY;
        
@@ -4038,7 +4056,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;
        }
@@ -4103,10 +4122,68 @@ static void imapaint_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, short toru
        }
 }
 
+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)
 {
-       IMB_rectblend_torus(ibufb, ibuf, 0, 0, pos[0], pos[1],
-               ibufb->x, ibufb->y, IMB_BLEND_COPY_RGB);
+       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, ibuf, ibufb);
+
+       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)
@@ -4136,12 +4213,14 @@ static void imapaint_convert_brushco(ImBuf *ibufb, float *pos, int *ipos)
 static int imapaint_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *pos)
 {
        ImagePaintState *s= ((ImagePaintState*)state);
-       ImBuf *clonebuf= NULL;
+       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);
 
@@ -4164,16 +4243,29 @@ static int imapaint_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *p
                clonebuf= imapaint_lift_clone(s->clonecanvas, ibufb, bliftpos);
        }
 
-       imapaint_dirty_region(s->image, s->canvas, bpos[0], bpos[1], ibufb->x, ibufb->y);
+       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 */
-       if(torus)
-               IMB_rectblend_torus(s->canvas, (clonebuf)? clonebuf: ibufb,
-                       bpos[0], bpos[1], 0, 0, ibufb->x, ibufb->y, blend);
-       else
-               IMB_rectblend(s->canvas, (clonebuf)? clonebuf: ibufb,
-                       bpos[0], bpos[1], 0, 0, ibufb->x, ibufb->y, blend);
-                       
+       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;
@@ -4184,14 +4276,14 @@ static int imapaint_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *p
 static int texpaint_break_stroke(float *prevuv, float *fwuv, float *bkuv, float *uv)
 {
        float d1[2], d2[2];
-       float mismatch = Vec2Lenf(fwuv, uv);
-       float len1 = Vec2Lenf(prevuv, fwuv);
-       float len2 = Vec2Lenf(bkuv, uv);
+       float mismatch = len_v2v2(fwuv, uv);
+       float len1 = len_v2v2(prevuv, fwuv);
+       float len2 = len_v2v2(bkuv, uv);
 
-       Vec2Subf(d1, fwuv, prevuv);
-       Vec2Subf(d2, uv, bkuv);
+       sub_v2_v2v2(d1, fwuv, prevuv);
+       sub_v2_v2v2(d2, uv, bkuv);
 
-       return ((Inp2f(d1, d2) < 0.0f) || (mismatch > MAX2(len1, len2)*2));
+       return ((dot_v2v2(d1, d2) < 0.0f) || (mismatch > MAX2(len1, len2)*2));
 }
 
 /* ImagePaint Common */
@@ -4201,7 +4293,10 @@ static int imapaint_canvas_set(ImagePaintState *s, Image *ima)
        ImBuf *ibuf= BKE_image_get_ibuf(ima, s->sima? &s->sima->iuser: NULL);
        
        /* verify that we can paint and set canvas */
-       if(ima->packedfile && ima->rr) {
+       if(ima==NULL) {
+               return 0;
+       }
+       else if(ima->packedfile && ima->rr) {
                s->warnpackedfile = ima->id.name + 2;
                return 0;
        }       
@@ -4209,7 +4304,7 @@ static int imapaint_canvas_set(ImagePaintState *s, Image *ima)
                s->warnmultifile = ima->id.name + 2;
                return 0;
        }
-       else if(!ima || !ibuf || !(ibuf->rect || ibuf->rect_float))
+       else if(!ibuf || !(ibuf->rect || ibuf->rect_float))
                return 0;
 
        s->image= ima;
@@ -4225,10 +4320,17 @@ static int imapaint_canvas_set(ImagePaintState *s, Image *ima)
 
                s->clonecanvas= ibuf;
 
+               /* temporarily add float rect for cloning */
                if(s->canvas->rect_float && !s->clonecanvas->rect_float) {
-                       /* temporarily add float rect for cloning */
+                       int profile = IB_PROFILE_NONE;
+                       
+                       /* Don't want to color manage, but don't disturb existing profiles */
+                       SWAP(int, s->clonecanvas->profile, profile);
+
                        IMB_float_from_rect(s->clonecanvas);
                        s->clonefreefloat= 1;
+                       
+                       SWAP(int, s->clonecanvas->profile, profile);
                }
                else if(!s->canvas->rect_float && !s->clonecanvas->rect)
                        IMB_rect_from_float(s->clonecanvas);
@@ -4274,7 +4376,7 @@ static int imapaint_paint_stroke(ViewContext *vc, ImagePaintState *s, BrushPaint
        if (texpaint) {
                /* pick new face and image */
                if (    imapaint_pick_face(vc, s->me, mval, &newfaceindex) &&
-                               ((G.f & G_FACESELECT)==0 || (s->me->mface+newfaceindex)->flag & ME_FACE_SEL)
+                               ((s->me->editflag & ME_EDIT_PAINT_MASK)==0 || (s->me->mface+newfaceindex)->flag & ME_FACE_SEL)
                ) {
                        ImBuf *ibuf;
                        
@@ -4282,7 +4384,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;
@@ -4293,8 +4395,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);
@@ -4305,7 +4407,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();
@@ -4388,12 +4490,10 @@ static int image_paint_3d_poll(bContext *C)
 
 static int image_paint_2d_clone_poll(bContext *C)
 {
-       Scene *scene= CTX_data_scene(C);
-       ToolSettings *settings= scene->toolsettings;
        Brush *brush= image_paint_brush(C);
 
        if(!CTX_wm_region_view3d(C) && image_paint_poll(C))
-               if(brush && (settings->imapaint.tool == PAINT_TOOL_CLONE))
+               if(brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE))
                        if(brush->clone.image)
                                return 1;
        
@@ -4418,7 +4518,7 @@ 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;
@@ -4431,29 +4531,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)
@@ -4463,21 +4542,74 @@ static void paint_redraw(bContext *C, ImagePaintState *s, int final)
        }
 }
 
+/* initialize project paint settings from context */
+static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps)
+{
+       Scene *scene= CTX_data_scene(C);
+       ToolSettings *settings= scene->toolsettings;
+       Brush *brush= paint_brush(&settings->imapaint.paint);
+
+       /* brush */
+       ps->brush = brush;
+       ps->tool = brush->imagepaint_tool;
+       ps->blend = brush->blend;
+
+       ps->is_airbrush = (brush->flag & BRUSH_AIRBRUSH) ? 1 : 0;
+       ps->is_texbrush = (brush->mtex.tex) ? 1 : 0;
+
+
+       /* these can be NULL */
+       ps->v3d= CTX_wm_view3d(C);
+       ps->rv3d= CTX_wm_region_view3d(C);
+       ps->ar= CTX_wm_region(C);
+
+       ps->scene= scene;
+       ps->ob= ob; /* allow override of active object */
+
+       /* setup projection painting data */
+       ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1;
+       ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1;
+       ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? 0 : 1;
+
+       if (ps->tool == PAINT_TOOL_CLONE)
+               ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE);
+
+       ps->do_layer_stencil = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? 1 : 0;
+       ps->do_layer_stencil_inv = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) ? 1 : 0;
+
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+       ps->seam_bleed_px = settings->imapaint.seam_bleed; /* pixel num to bleed */
+#endif
+
+       if(ps->do_mask_normal) {
+               ps->normal_angle_inner = settings->imapaint.normal_angle;
+               ps->normal_angle = (ps->normal_angle_inner + 90.0f) * 0.5f;
+       }
+       else {
+               ps->normal_angle_inner= ps->normal_angle= settings->imapaint.normal_angle;
+       }
+
+       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)
+               ps->do_mask_normal = 0; /* no need to do blending */
+}
+
 static int texture_paint_init(bContext *C, wmOperator *op)
 {
        Scene *scene= CTX_data_scene(C);
        ToolSettings *settings= scene->toolsettings;
-       PaintOperation *pop;
-       Brush *brush;
+       Brush *brush= paint_brush(&settings->imapaint.paint);
+       PaintOperation *pop= MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */
 
-       pop= MEM_callocN(sizeof(PaintOperation), "PaintOperation");
        pop->first= 1;
        op->customdata= pop;
        
        /* initialize from context */
        if(CTX_wm_region_view3d(C)) {
-               pop->ps.v3d= CTX_wm_view3d(C);
-               pop->ps.rv3d= CTX_wm_region_view3d(C);
                pop->mode= PAINT_MODE_3D;
 
                if(!(settings->imapaint.flag & IMAGEPAINT_PROJECT_DISABLE))
@@ -4491,43 +4623,24 @@ static int texture_paint_init(bContext *C, wmOperator *op)
        }
 
        pop->s.scene= scene;
-       pop->ps.scene= scene;
        pop->s.screen= CTX_wm_screen(C);
-       pop->ps.ar= CTX_wm_region(C);
-
-       /* intialize brush */
-       brush= paint_brush(&settings->imapaint.paint);
-       if(!brush)
-               return 0;
 
        pop->s.brush = brush;
-       pop->s.tool = settings->imapaint.tool;
+       pop->s.tool = brush->imagepaint_tool;
        if(pop->mode == PAINT_MODE_3D && (pop->s.tool == PAINT_TOOL_CLONE))
                pop->s.tool = PAINT_TOOL_DRAW;
-       pop->s.blend = pop->s.brush->blend;
-       
-       if(pop->mode == PAINT_MODE_3D_PROJECT) {
-               pop->ps.brush = pop->s.brush;
-               pop->ps.tool = pop->s.tool;
-               pop->ps.blend = pop->s.blend;
-
-               pop->brush_size_orig = pop->ps.brush->size; /* not nice hack because 1 size brushes always fail with projection paint */
-       }
+       pop->s.blend = brush->blend;
+       pop->orig_brush_size= brush_size(brush);
 
        if(pop->mode != PAINT_MODE_2D) {
-               pop->ps.ob = pop->s.ob = OBACT;
-               if (!pop->s.ob || !(pop->s.ob->lay & pop->ps.v3d->lay)) return 0;
+               pop->s.ob = OBACT;
                pop->s.me = get_mesh(pop->s.ob);
                if (!pop->s.me) return 0;
-
-               /* Dont allow brush size below 2 */
-               if (pop->ps.brush && pop->ps.brush->size<=1)
-                       pop->ps.brush->size = 2;
        }
        else {
                pop->s.image = pop->s.sima->image;
 
-               if(!imapaint_canvas_set(&pop->s, 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)
@@ -4536,40 +4649,23 @@ static int texture_paint_init(bContext *C, wmOperator *op)
                        return 0;
                }
        }
-       
+
        /* note, if we have no UVs on the derived mesh, then we must return here */
        if(pop->mode == PAINT_MODE_3D_PROJECT) {
-               /* setup projection painting data */
-               pop->ps.do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1;
-               pop->ps.do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1;
-               pop->ps.do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? 0 : 1;;
-               
-               if (pop->ps.tool == PAINT_TOOL_CLONE)
-                       pop->ps.do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE);
-               
-               pop->ps.do_layer_mask = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_MASK) ? 1 : 0;
-               pop->ps.do_layer_mask_inv = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_MASK_INV) ? 1 : 0;
-               
-               
-#ifndef PROJ_DEBUG_NOSEAMBLEED
-               pop->ps.seam_bleed_px = settings->imapaint.seam_bleed; /* pixel num to bleed */
-#endif
 
-               if(pop->ps.do_mask_normal) {
-                       pop->ps.normal_angle_inner = settings->imapaint.normal_angle;
-                       pop->ps.normal_angle = (pop->ps.normal_angle_inner + 90.0f) * 0.5f;
-               }
-               else {
-                       pop->ps.normal_angle_inner= pop->ps.normal_angle= settings->imapaint.normal_angle;
-               }
+               /* initialize all data from the context */
+               project_state_init(C, OBACT, &pop->ps);
 
-               pop->ps.normal_angle_inner *=   M_PI_2 / 90;
-               pop->ps.normal_angle *=                 M_PI_2 / 90;
-               pop->ps.normal_angle_range = pop->ps.normal_angle - pop->ps.normal_angle_inner;
-               
-               if(pop->ps.normal_angle_range <= 0.0f)
-                       pop->ps.do_mask_normal = 0; /* no need to do blending */
+               pop->ps.source= PROJ_SRC_VIEW;
+
+               if (pop->ps.ob==NULL || !(pop->ps.ob->lay & pop->ps.v3d->lay))
+                       return 0;
+
+               /* Dont allow brush size below 2 */
+               if (brush_size(brush) < 2)
+                       brush_set_size(brush, 2);
 
+               /* allocate and initialize spacial data structures */
                project_paint_begin(&pop->ps);
                
                if(pop->ps.dm==NULL)
@@ -4577,7 +4673,8 @@ static int texture_paint_init(bContext *C, wmOperator *op)
        }
        
        settings->imapaint.flag |= IMAGEPAINT_DRAWING;
-       undo_imagepaint_push_begin("Image Paint");
+       undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
+               image_undo_restore, image_undo_free);
 
        /* create painter */
        pop->painter= brush_painter_new(pop->s.brush);
@@ -4593,8 +4690,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");
 
@@ -4629,19 +4726,19 @@ static void paint_exit(bContext *C, wmOperator *op)
        PaintOperation *pop= op->customdata;
 
        if(pop->timer)
-               WM_event_remove_window_timer(CTX_wm_window(C), pop->timer);
+               WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), pop->timer);
 
        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);
        }
        
        paint_redraw(C, &pop->s, 1);
-       undo_imagepaint_push_end();
+       undo_paint_push_end(UNDO_PAINT_IMAGE);
        
        if(pop->s.warnmultifile)
                BKE_reportf(op->reports, RPT_WARNING, "Image requires 4 color channels to paint: %s", pop->s.warnmultifile);
@@ -4707,15 +4804,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);
@@ -4741,7 +4845,7 @@ static int paint_invoke(bContext *C, wmOperator *op, wmEvent *event)
        WM_event_add_modal_handler(C, op);
 
        if(pop->s.brush->flag & BRUSH_AIRBRUSH)
-               pop->timer= WM_event_add_window_timer(CTX_wm_window(C), TIMER, 0.01f);
+               pop->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
 
        return OPERATOR_RUNNING_MODAL;
 }
@@ -4757,6 +4861,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:
@@ -4815,12 +4920,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);
@@ -4828,13 +4938,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();
        }
 }
@@ -4858,7 +4968,7 @@ static int paint_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *eve
        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);
+       brush_radial_control_invoke(op, paint_brush(&ts->imapaint.paint), zoom);
        return WM_radial_control_invoke(C, op, event);
 }
 
@@ -4867,7 +4977,7 @@ static int paint_radial_control_modal(bContext *C, wmOperator *op, wmEvent *even
        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, !ts->imapaint.paintcursor);
        return ret;
 }
 
@@ -4876,10 +4986,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);
 
@@ -4915,9 +5025,7 @@ static void grab_clone_apply(bContext *C, wmOperator *op)
        float delta[2];
 
        RNA_float_get_array(op->ptr, "delta", delta);
-       brush->clone.offset[0] += delta[0];
-       brush->clone.offset[1] += delta[1];
-
+       add_v2_v2(brush->clone.offset, delta);
        ED_region_tag_redraw(CTX_wm_region(C));
 }
 
@@ -4934,8 +5042,7 @@ static int grab_clone_invoke(bContext *C, wmOperator *op, wmEvent *event)
        GrabClone *cmv;
 
        cmv= MEM_callocN(sizeof(GrabClone), "GrabClone");
-       cmv->startoffset[0]= brush->clone.offset[0];
-       cmv->startoffset[1]= brush->clone.offset[1];
+       copy_v2_v2(cmv->startoffset, brush->clone.offset);
        cmv->startx= event->x;
        cmv->starty= event->y;
        op->customdata= cmv;
@@ -4968,8 +5075,7 @@ static int grab_clone_modal(bContext *C, wmOperator *op, wmEvent *event)
                        delta[1]= fy - startfy;
                        RNA_float_set_array(op->ptr, "delta", delta);
 
-                       brush->clone.offset[0]= cmv->startoffset[0];
-                       brush->clone.offset[1]= cmv->startoffset[1];
+                       copy_v2_v2(brush->clone.offset, cmv->startoffset);
 
                        grab_clone_apply(C, op);
                        break;
@@ -4978,7 +5084,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;
@@ -5026,11 +5132,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);
+       }
 
-       return 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 OPERATOR_RUNNING_MODAL;
 }
 
 void PAINT_OT_sample_color(wmOperatorType *ot)
@@ -5042,6 +5177,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 */
@@ -5189,16 +5325,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);
 
@@ -5231,8 +5367,211 @@ void PAINT_OT_texture_paint_radial_control(wmOperatorType *ot)
        ot->exec= texture_paint_radial_control_exec;
        ot->poll= texture_paint_poll;
        
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
+}
+
+
+int facemask_paint_poll(bContext *C)
+{
+       return paint_facesel_test(CTX_data_active_object(C));
+}
+
+/* use project paint to re-apply an image */
+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;
+       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) {
+               BKE_report(op->reports, RPT_ERROR, "No active mesh object.");
+               return OPERATOR_CANCELLED;
+       }
+
+       if(image==NULL) {
+               BKE_report(op->reports, RPT_ERROR, "Image could not be found.");
+               return OPERATOR_CANCELLED;
+       }
+
+       ps.reproject_image= image;
+       ps.reproject_ibuf= BKE_image_get_ibuf(image, NULL);
+
+       if(ps.reproject_ibuf==NULL || ps.reproject_ibuf->rect==NULL) {
+               BKE_report(op->reports, RPT_ERROR, "Image data could not be found.");
+               return OPERATOR_CANCELLED;
+       }
+
+       idgroup= IDP_GetProperties(&image->id, 0);
+
+       if(idgroup) {
+               view_data= IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID);
+
+               /* type check to make sure its ok */
+               if(view_data->len != PROJ_VIEW_DATA_SIZE || view_data->type != IDP_ARRAY || view_data->subtype != IDP_FLOAT) {
+                       BKE_report(op->reports, RPT_ERROR, "Image project data invalid.");
+                       return OPERATOR_CANCELLED;
+               }
+       }
+
+       if(view_data) {
+               /* image has stored view projection info */
+               ps.source= PROJ_SRC_IMAGE_VIEW;
+       }
+       else {
+               ps.source= PROJ_SRC_IMAGE_CAM;
+
+               if(scene->camera==NULL) {
+                       BKE_report(op->reports, RPT_ERROR, "No active camera set.");
+                       return OPERATOR_CANCELLED;
+               }
+       }
+
+       /* override */
+       ps.is_texbrush= 0;
+       ps.is_airbrush= 1;
+       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, op->type->name,
+               image_undo_restore, image_undo_free);
+
+       /* allocate and initialize spacial data structures */
+       project_paint_begin(&ps);
+
+       if(ps.dm==NULL) {
+               brush_set_size(ps.brush, orig_brush_size);
+               return OPERATOR_CANCELLED;
+       }
+       else {
+               float pos[2]= {0.0, 0.0};
+               float lastpos[2]= {0.0, 0.0};
+               int a;
+
+               for (a=0; a < ps.image_tot; a++)
+                       partial_redraw_array_init(ps.projImages[a].partRedrawRect);
+
+               project_paint_op(&ps, NULL, lastpos, pos);
+
+               project_image_refresh_tagged(&ps);
+
+               for (a=0; a < ps.image_tot; a++) {
+                       GPU_free_image(ps.projImages[a].ima);
+                       WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ps.projImages[a].ima);
+               }
+       }
+
+       project_paint_end(&ps);
+
+       scene->toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
+       brush_set_size(ps.brush, orig_brush_size);
+
+       return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_project_image(wmOperatorType *ot)
+{
+       PropertyRNA *prop;
+
+       /* identifiers */
+       ot->name= "Project Image";
+       ot->idname= "PAINT_OT_project_image";
+       ot->description= "Project an edited render from the active camera back onto the object";
+
+       /* api callbacks */
+       ot->invoke= WM_enum_search_invoke;
+       ot->exec= texture_paint_camera_project_exec;
+
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       prop= RNA_def_enum(ot->srna, "image", DummyRNA_NULL_items, 0, "Image", "");
+       RNA_def_enum_funcs(prop, RNA_image_itemf);
+       ot->prop= prop;
 }
 
+static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
+{
+       Image *image;
+       ImBuf *ibuf;
+       char filename[FILE_MAX];
 
+       Scene *scene= CTX_data_scene(C);
+       ToolSettings *settings= scene->toolsettings;
+       int w= settings->imapaint.screen_grab_size[0];
+       int h= settings->imapaint.screen_grab_size[1];
+       int maxsize;
+
+       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, 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) {
+               /* now for the trickyness. store the view projection here!
+                * reprojection will reuse this */
+               View3D *v3d= CTX_wm_view3d(C);
+               RegionView3D *rv3d= CTX_wm_region_view3d(C);
+
+               IDPropertyTemplate val;
+               IDProperty *idgroup= IDP_GetProperties(&image->id, 1);
+               IDProperty *view_data;
+               int orth;
+               float *array;
+
+               val.array.len = PROJ_VIEW_DATA_SIZE;
+               val.array.type = IDP_FLOAT;
+               view_data = IDP_New(IDP_ARRAY, val, PROJ_VIEW_DATA_ID);
+
+               array= (float *)IDP_Array(view_data);
+               memcpy(array, rv3d->winmat, sizeof(rv3d->winmat)); array += sizeof(rv3d->winmat)/sizeof(float);
+               memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat)); array += sizeof(rv3d->viewmat)/sizeof(float);
+               orth= project_paint_view_clip(v3d, rv3d, &array[0], &array[1]);
+               array[2]= orth ? 1.0f : 0.0f; /* using float for a bool is dodgy but since its an extra member in the array... easier then adding a single bool prop */
+
+               IDP_AddToGroup(idgroup, view_data);
+
+               rename_id(&image->id, "image_view");
+       }
+
+       return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_image_from_view(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Image from View";
+       ot->idname= "PAINT_OT_image_from_view";
+       ot->description= "Make an image from the current 3D view for re-projection";
+
+       /* api callbacks */
+       ot->exec= texture_paint_image_from_view_exec;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER;
+
+       RNA_def_string_file_name(ot->srna, "filepath", "", FILE_MAX, "File Path", "Name of the file");
+}