svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r17279:HEAD
authorCampbell Barton <ideasman42@gmail.com>
Wed, 5 Nov 2008 15:11:40 +0000 (15:11 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 5 Nov 2008 15:11:40 +0000 (15:11 +0000)
somehow scripts line endings change is messing things up, these changes wont be included
error is:
svn: File 'release/scripts/scripttemplate_metaball_create.py' has inconsistent newlines
svn: Inconsistent line ending style
svn: Error reading spooled REPORT request response

release/scripts/export_m3g.py
release/scripts/image_auto_layout.py
release/scripts/import_lightwave_motion.py
release/scripts/scripttemplate_gamelogic.py
source/blender/src/imagepaint.c

index c74e7acbcd37fff72e9e7b6abf6b4b88ddb89e65..86ac03cc407a97134c3a32d41122f097cd7d5bdd 100644 (file)
@@ -11,7 +11,7 @@ Tooltip: 'Export to M3G'
 #
 # Source: http://www.nelson-games.de/bl2m3g/source
 #
-# $Id$
+# $Id: m3g_export.py,v 0.1 2005/04/19 12:25 gerhardv Exp gerhardv $
 #
 # Author: Gerhard Völkl
 #
index c6f97a25434f9ae00da9091f528ca3e3003b433d..19ee396c3b1d2671cbe1fa78ff0008a2c36c54cc 100644 (file)
@@ -265,8 +265,8 @@ def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PR
        render_context.setRenderWinSize(100)
        render_context.setImageType(Render.PNG)
        render_context.enableExtensions(True) 
-       render_context.enablePremultiply() # No alpha needed.
-       render_context.enableRGBAColor()
+       render_context.enableSky() # No alpha needed.
+       render_context.enableRGBColor()
        render_context.threads = 2
        
        #Render.EnableDispView() # Broken??
@@ -275,9 +275,8 @@ def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PR
        render_mat= B.Material.New()
        render_mat.mode |= B.Material.Modes.SHADELESS
        render_mat.mode |= B.Material.Modes.TEXFACE
-       render_mat.mode |= B.Material.Modes.ZTRANSP
-       render_mat.setAlpha(0.0)
-               
+       
+       
        render_me= B.Mesh.New()
        render_me.verts.extend([Vector(0,0,0)]) # Stupid, dummy vert, preverts errors. when assigning UV's/
        render_ob= B.Object.New('Mesh')
index 20c87dfd5c633761db1b14fa5e8234d077f6bf16..c242a9f6bd3ee9507de7848c48ee0d06e056fcc2 100644 (file)
@@ -22,7 +22,7 @@ Be sure to set the framerate correctly
 
 """
 
-# $Id$
+# $Id: export_lightwave_motion.py 9924 2007-01-27 02:15:14Z campbellbarton $
 # --------------------------------------------------------------------------
 # ***** BEGIN GPL LICENSE BLOCK *****
 #
index 7184d7e424fcf3e2344660c2b2e1661d1b7fb5ba..1709525115500c5ee716f70a19b679376d3d937d 100644 (file)
@@ -83,8 +83,7 @@ def main():
                        own.life += ob.life
                        ob.life = 0
        print own.life
-       """
-
+       """\r
 main()
 '''
 
index 149dbf1d0268151f6f1453486260848fe86a1995..119e174a71d647ce634b324458ebf627ce86f99f 100644 (file)
@@ -23,9 +23,9 @@
  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  * All rights reserved.
  *
- * The Original Code is: all of this file.
+ * The Original Code is: some of this file.
  *
- * Contributor(s): Jens Ole Wund (bjornmose)
+ * Contributor(s): Jens Ole Wund (bjornmose), Campbell Barton (ideasman42)
  *
  * ***** END GPL LICENSE BLOCK *****
  */
@@ -46,6 +46,8 @@
 #include "BLI_arithb.h"
 #include "BLI_blenlib.h"
 #include "BLI_dynstr.h"
+#include "BLI_linklist.h"
+#include "BLI_memarena.h"
 #include "PIL_time.h"
 
 #include "IMB_imbuf.h"
@@ -70,6 +72,7 @@
 #include "BKE_mesh.h"
 #include "BKE_node.h"
 #include "BKE_utildefines.h"
+#include "BKE_DerivedMesh.h"
 
 #include "BIF_interface.h"
 #include "BIF_mywindow.h"
@@ -126,6 +129,104 @@ typedef struct ImagePaintState {
        float uv[2];
 } ImagePaintState;
 
+
+/* testing options */
+#define PROJ_BUCKET_DIV 128 /* TODO - test other values, this is a guess, seems ok */
+
+// #define PROJ_DEBUG_PAINT 1
+// #define PROJ_DEBUG_NOSCANLINE 1
+
+/* projectFaceFlags options */
+#define PROJ_FACE_IGNORE       1<<0    /* When the face is hidden, backfacing or occluded */
+#define PROJ_FACE_INIT 1<<1    /* When we have initialized the faces data */
+#define PROJ_FACE_SEAM1        1<<2    /* If this face has a seam on any of its edges */
+#define PROJ_FACE_SEAM2        1<<3
+#define PROJ_FACE_SEAM3        1<<4
+#define PROJ_FACE_SEAM4        1<<5
+
+
+#define PROJ_BUCKET_NULL               0
+#define PROJ_BUCKET_INIT               1<<0
+// #define PROJ_BUCKET_CLONE_INIT      1<<1
+
+/* only for readability */
+#define PROJ_BUCKET_LEFT               0
+#define PROJ_BUCKET_RIGHT      1
+#define PROJ_BUCKET_BOTTOM     2
+#define PROJ_BUCKET_TOP                3
+
+typedef struct ProjectPaintState {
+       Brush *brush;
+       short tool, blend;
+       Object *ob;
+       /* end similarities with ImagePaintState */
+       
+       DerivedMesh    *dm;
+       int                     dm_totface;
+       int                     dm_totvert;
+       
+       MVert              *dm_mvert;
+       MFace              *dm_mface;
+       MTFace             *dm_mtface;
+       
+       /* projection painting only */
+       MemArena *projectArena;         /* use for alocating many pixel structs and link-lists */
+       LinkNode **projectBuckets;      /* screen sized 2D array, each pixel has a linked list of ProjectPixel's */
+       LinkNode **projectFaces;        /* projectBuckets alligned array linkList of faces overlapping each bucket */
+       char *projectBucketFlags;       /* store if the bucks have been initialized  */
+       char *projectFaceFlags;         /* store info about faces, if they are initialized etc*/
+       LinkNode **projectVertFaces;/* Only needed for when projectIsSeamBleed is enabled, use to find UV seams */
+       
+       int bucketsX;                           /* The size of the bucket grid, the grid span's viewMin2D/viewMax2D so you can paint outsize the screen or with 2 brushes at once */
+       int bucketsY;
+       
+       Image **projectImages;          /* array of images we are painting onto while, use so we can tag for updates */
+       int projectImageTotal;          /* size of projectImages array */
+       int image_index;                        /* current image, use for context switching */
+       
+       float (*projectVertScreenCos)[3];       /* verts projected into floating point screen space */
+       
+       /* options for projection painting */
+       short projectIsOcclude;         /* Use raytraced occlusion? - ortherwise will paint right through to the back*/
+       short projectIsBackfaceCull;    /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */
+       short projectIsOrtho;
+       float projectSeamBleed;
+       
+       /* clone vars */
+       float cloneOfs[2];
+       
+       
+       float projectMat[4][4];         /* Projection matrix, use for getting screen coords */
+       float viewMat[4][4];
+       float viewDir[3];                       /* View vector, use for projectIsBackfaceCull and for ray casting with an ortho viewport  */
+       
+       float viewMin2D[2];                     /* 2D bounds for mesh verts on the screen's plane (screenspace) */
+       float viewMax2D[2]; 
+       float viewWidth;                        /* Calculated from viewMin2D & viewMax2D */
+       float viewHeight;
+} ProjectPaintState;
+
+typedef struct ProjectScanline {
+       int v[3]; /* verts for this scanline, 0,1,2 or 0,2,3 */
+       float x_limits[2]; /* UV min|max for this scanline */
+} ProjectScanline;
+
+typedef struct ProjectPixel {
+       float projCo2D[2]; /* the floating point screen projection of this pixel */
+       char *pixel;
+       int image_index;
+} ProjectPixel;
+
+typedef struct ProjectPixelClone {
+       struct ProjectPixel __pp;
+       char backbuf[4];        /* TODO - float buffer? */
+       char clonebuf[4];
+       //void *source;         /* pointer to source pixels */
+} ProjectPixelClone;
+
+/* Finish projection painting structs */
+
+
 typedef struct UndoTile {
        struct UndoTile *next, *prev;
        ID id;
@@ -281,6 +382,1374 @@ static void undo_imagepaint_push_end()
        }
 }
 
+
+static int project_paint_BucketOffset(ProjectPaintState *ps, float *projCo2D)
+{
+       /* If we were not dealing with screenspace 2D coords we could simple do...
+        * ps->projectBuckets[x + (y*ps->bucketsY)] */
+       
+       /* please explain?
+        * projCo2D[0] - ps->viewMin2D[0]       : zero origin
+        * ... / ps->viewWidth                          : range from 0.0 to 1.0
+        * ... * ps->bucketsX           : use as a bucket index
+        *
+        * Second multiplication does similar but for vertical offset
+        */
+       return  (       (int)(( (projCo2D[0] - ps->viewMin2D[0]) / ps->viewWidth)  * ps->bucketsX)) + 
+               (       (       (int)(( (projCo2D[1] - ps->viewMin2D[1])  / ps->viewHeight) * ps->bucketsY)) * ps->bucketsX );
+}
+
+static int project_paint_BucketOffsetSafe(ProjectPaintState *ps, float *projCo2D)
+{
+       int bucket_index = project_paint_BucketOffset(ps, projCo2D);
+       
+       if (bucket_index < 0 || bucket_index >= ps->bucketsX*ps->bucketsY) {    
+               return -1;
+       } else {
+               return bucket_index;
+       }
+}
+
+/* assume they intersect */
+static void BarryCentricWeights2f(float v1[2], float v2[2], float v3[2], float pt[2], float w[3]) {
+       float wtot;
+       w[0] = AreaF2Dfl(v2, v3, pt);
+       w[1] = AreaF2Dfl(v3, v1, pt);
+       w[2] = AreaF2Dfl(v1, v2, pt);
+       wtot = w[0]+w[1]+w[2];
+       w[0]/=wtot;
+       w[1]/=wtot;
+       w[2]/=wtot;
+}
+
+static float tri_depth_2d(float v1[3], float v2[3], float v3[3], float pt[2], float w[3])
+{
+       BarryCentricWeights2f(v1,v2,v3,pt,w);
+       return (v1[2]*w[0]) + (v2[2]*w[1]) + (v3[2]*w[2]);
+}
+
+
+/* return the topmost face  in screen coords index or -1
+ * bucket_index can be -1 if we dont know it to begin with */
+static int screenco_pickface(ProjectPaintState *ps, float pt[2], float w[3], int *side) {
+       LinkNode *node;
+       float w_tmp[3];
+       float *v1, *v2, *v3, *v4;
+       int bucket_index;
+       int face_index;
+       int best_side = -1;
+       int best_face_index = -1;
+       float z_depth_best = MAXFLOAT, z_depth;
+       MFace *mf;
+       
+       bucket_index = project_paint_BucketOffsetSafe(ps, pt);
+       if (bucket_index==-1)
+               return -1;
+       
+       node = ps->projectFaces[bucket_index];
+       
+       /* we could return 0 for 1 face buckets, as long as this function assumes
+        * that the point its testing is only every originated from an existing face */
+       
+       while (node) {
+               face_index = (int)node->link;
+               mf = ps->dm_mface + face_index;
+               
+               v1 = ps->projectVertScreenCos[mf->v1];
+               v2 = ps->projectVertScreenCos[mf->v2];
+               v3 = ps->projectVertScreenCos[mf->v3];
+               
+               if ( IsectPT2Df(pt, v1, v2, v3) ) {
+                       z_depth = tri_depth_2d(v1,v2,v3,pt,w_tmp);
+                       if (z_depth < z_depth_best) {
+                               best_face_index = face_index;
+                               best_side = 0;
+                               z_depth_best = z_depth;
+                               VECCOPY(w, w_tmp);
+                       }
+               } else if (mf->v4) {
+                       v4 = ps->projectVertScreenCos[mf->v4];
+                       
+                       if ( IsectPT2Df(pt, v1, v3, v4) ) {
+                               z_depth = tri_depth_2d(v1,v3,v4,pt,w_tmp);
+                               if (z_depth < z_depth_best) {
+                                       best_face_index = face_index;
+                                       best_side = 1;
+                                       z_depth_best = z_depth;
+                                       VECCOPY(w, w_tmp);
+                               }
+                       }
+               }
+               
+               node = node->next;
+       }
+       
+       *side = best_side;
+       return best_face_index; /* will be -1 or a valid face */
+}
+
+/* bucket_index is optional, since in some cases we know it */
+static int screenco_pickcol(ProjectPaintState *ps, int bucket_index, float pt[2], char rgba[4])
+{
+       float w[3], uv[2];
+       int side;
+       int face_index;
+       MTFace *tf;
+       ImBuf *ibuf;
+       int x,y;
+       char *pixel;
+       
+       face_index = screenco_pickface(ps,pt,w, &side);
+       
+       if (face_index == -1)
+               return 0;
+       
+       tf = ps->dm_mtface + face_index;
+       
+       if (side==0) {
+               uv[0] = tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[2][0]*w[2];
+               uv[1] = tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[2][1]*w[2];
+       } else { /* QUAD */
+               uv[0] = tf->uv[0][0]*w[0] + tf->uv[2][0]*w[1] + tf->uv[3][0]*w[2];
+               uv[1] = tf->uv[0][1]*w[0] + tf->uv[2][1]*w[1] + tf->uv[3][1]*w[2];
+       }
+       
+       ibuf = BKE_image_get_ibuf((Image *)tf->tpage, NULL); /* TODO - this may be slow */
+       
+       x = uv[0]*ibuf->x;
+       y = uv[1]*ibuf->y;
+       
+       if (x<0 || x>=ibuf->x  ||  y<0 || y>=ibuf->y) return 0;
+       
+       pixel = (( char * ) ibuf->rect) + (( x + y * ibuf->x ) * 4);
+       
+       rgba[0] = pixel[0];
+       rgba[1] = pixel[1];
+       rgba[2] = pixel[2];
+       rgba[3] = pixel[3];
+       return 1;
+}
+
+/* return...
+ * 0   : no occlusion
+ * -1  : no occlusion but 2D intersection is true (avoid testing the other half of a quad)
+ * 1   : occluded */
+
+static int screenco_tri_pt_occlude(float pt[3], float v1[3], float v2[3], float v3[3])
+{
+       /* if all are behind us, return false */
+       if(v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2])
+               return 0;
+               
+       /* do a 2D point in try intersection */
+       if ( !IsectPT2Df(pt, v1, v2, v3) )
+               return 0; /* we know there is  */
+       
+       /* From here on we know there IS an intersection */
+       
+       /* if ALL of the verts are infront of us then we know it intersects ? */
+       if(     v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) {
+               return 1;
+       } else {
+               float w[3];
+               /* we intersect? - find the exact depth at the point of intersection */
+               if (tri_depth_2d(v1,v2,v3,pt,w) < pt[2]) {
+                       return 1; /* This point is occluded by another face */
+               }
+       }
+       return -1;
+}
+
+
+/* check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be used for comparison */
+static int project_bucket_point_occluded(ProjectPaintState *ps, int bucket_index, int orig_face, float pixelScreenCo[4])
+{
+       LinkNode *node = ps->projectFaces[bucket_index];
+       MFace *mf;
+       int face_index;
+       int isect_ret;
+       
+       /* we could return 0 for 1 face buckets, as long as this function assumes
+        * that the point its testing is only every originated from an existing face */
+       
+       while (node) {
+               face_index = (int)node->link;
+               
+               if (orig_face != face_index) {
+                       
+                       mf = ps->dm_mface + face_index;
+                       
+                       isect_ret = screenco_tri_pt_occlude(
+                                       pixelScreenCo,
+                                       ps->projectVertScreenCos[mf->v1],
+                                       ps->projectVertScreenCos[mf->v2],
+                                       ps->projectVertScreenCos[mf->v3]);
+                       
+                       /* Note, if isect_ret==-1 then we dont want to test the other side of the quad */
+                       if (isect_ret==0 && mf->v4) {
+                               isect_ret = screenco_tri_pt_occlude(
+                                               pixelScreenCo,
+                                               ps->projectVertScreenCos[mf->v1],
+                                               ps->projectVertScreenCos[mf->v3],
+                                               ps->projectVertScreenCos[mf->v4]);
+                       }
+                       
+                       if (isect_ret==1) {
+                               /* Cheap Optimization!
+                                * This function runs for every UV Screen pixel,
+                                * therefor swapping the swapping the faces for this buckets list helps because
+                                * the next ~5 to ~200 runs will can hit the first face each time. */
+                               if (ps->projectFaces[bucket_index] != node) {
+                                       /* SWAP(void *, ps->projectFaces[bucket_index]->link, node->link); */
+                                       
+                                       /* dont need to use swap since we alredy have face_index */
+                                       node->link = ps->projectFaces[bucket_index]->link; /* move the value item to the current value */
+                                       ps->projectFaces[bucket_index]->link = (void *) face_index;
+                                       
+                                       /*printf("swapping %d %d\n", (int)node->link, face_index);*/
+                               } /*else {
+                                       printf("first hit %d\n", face_index);
+                               }*/
+                               
+                               return 1; 
+                       }
+               }
+               node = node->next;
+       }
+       
+       return 0;
+}
+
+/* basic line intersection, could move to arithb.c, 2 points with a horiz line
+ * 1 for an intersection, 2 if the first point is aligned, 3 if the second point is aligned */
+#define ISECT_TRUE 1
+#define ISECT_TRUE_P1 2
+#define ISECT_TRUE_P2 3
+static int project_scanline_isect(float p1[2], float p2[2], float y_level, float *x_isect)
+{
+       if (y_level==p1[1]) {
+               *x_isect = p1[0];
+               return ISECT_TRUE_P1;
+       }
+       if (y_level==p2[1]) {
+               *x_isect = p2[0];
+               return ISECT_TRUE_P2;
+       }
+       
+       if (p1[1] > y_level && p2[1] < y_level) {
+               *x_isect = (p2[0]*(p1[1]-y_level) + p1[0]*(y_level-p2[1])) / (p1[1]-p2[1]);
+               return ISECT_TRUE;
+       } else if (p1[1] < y_level && p2[1] > y_level) {
+               *x_isect = (p2[0]*(y_level-p1[1]) + p1[0]*(p2[1]-y_level)) / (p2[1]-p1[1]);
+               return ISECT_TRUE;
+       } else {
+               return 0;
+       }
+}
+
+static int project_face_scanline(ProjectScanline *sc, float y_level, float v1[2], float v2[2], float v3[2], float v4[2])
+{      
+       /* Create a scanlines for the face at this Y level 
+        * triangles will only ever have 1 scanline, quads may have 2 */
+       int totscanlines = 0;
+       short i1=0,i2=0,i3=0;
+       
+       if (v4) { /* This is a quad?*/
+               int i4=0, i_mid=0;
+               float xi1, xi2, xi3, xi4, xi_mid;
+                               
+               i1 = project_scanline_isect(v1, v2, y_level, &xi1);
+               if (i1 != ISECT_TRUE_P2) /* rare cases we could be on the line, in these cases we dont want to intersect with the same point twice */
+                       i2 = project_scanline_isect(v2, v3, y_level, &xi2);
+               
+               if (i1 && i2) { /* both the first 2 edges intersect, this means the second half of the quad wont intersect */
+                       sc->v[0] = 0;
+                       sc->v[1] = 1;
+                       sc->v[2] = 2;
+                       sc->x_limits[0] = MIN2(xi1, xi2);
+                       sc->x_limits[1] = MAX2(xi1, xi2);
+                       totscanlines = 1;
+               } else {
+                       if (i2 != ISECT_TRUE_P2) 
+                               i3 = project_scanline_isect(v3, v4, y_level, &xi3);
+                       if (i1 != ISECT_TRUE_P1 && i3 != ISECT_TRUE_P2) 
+                               i4 = project_scanline_isect(v4, v1, y_level, &xi4);
+                       
+                       if (i3 && i4) { /* second 2 edges only intersect, same as above */
+                               sc->v[0] = 0;
+                               sc->v[1] = 2;
+                               sc->v[2] = 3;
+                               sc->x_limits[0] = MIN2(xi3, xi4);
+                               sc->x_limits[1] = MAX2(xi3, xi4);
+                               totscanlines = 1;
+                       } else {
+                               /* OK - we have a not-so-simple case, both sides of the quad intersect.
+                                * Will need to have 2 scanlines */
+                               if ((i1||i2) && (i3||i4)) {
+                                       i_mid = project_scanline_isect(v1, v3, y_level, &xi_mid);
+                                       /* it would be very rare this would be false, but possible */
+                                       sc->v[0] = 0;
+                                       sc->v[1] = 1;
+                                       sc->v[2] = 2;
+                                       sc->x_limits[0] = MIN2((i1?xi1:xi2), xi_mid);
+                                       sc->x_limits[1] = MAX2((i1?xi1:xi2), xi_mid);
+                                       
+                                       sc++;
+                                       sc->v[0] = 0;
+                                       sc->v[1] = 2;
+                                       sc->v[2] = 3;
+                                       sc->x_limits[0] = MIN2((i3?xi3:xi4), xi_mid);
+                                       sc->x_limits[1] = MAX2((i3?xi3:xi4), xi_mid);
+                                       
+                                       totscanlines = 2;
+                               }
+                       }
+               }
+       } else { /* triangle */
+               int i = 0;
+               
+               i1 = project_scanline_isect(v1, v2, y_level, &sc->x_limits[0]);
+               if (i1) i++;
+               
+               if (i1 != ISECT_TRUE_P2) {
+                       i2 = project_scanline_isect(v2, v3, y_level, &sc->x_limits[i]);
+                       if (i2) i++;
+               }
+               
+               /* if the triangle intersects then the first 2 lines must */
+               if (i!=0) {
+                       if (i!=2) {
+                               /* if we are here then this really should not fail since 2 edges MUST intersect  */
+                               if (i1 != ISECT_TRUE_P1 && i2 != ISECT_TRUE_P2) {
+                                       i3 = project_scanline_isect(v3, v1, y_level, &sc->x_limits[i]);
+                                       if (i3) i++;
+                                       
+                               }
+                       }
+                       
+                       if (i==2) {
+                               if (sc->x_limits[0] > sc->x_limits[1]) {
+                                       SWAP(float, sc->x_limits[0], sc->x_limits[1]);
+                               }
+                               sc->v[0] = 0;
+                               sc->v[1] = 1;
+                               sc->v[2] = 2;
+                               totscanlines = 1;
+                       }
+               }
+       }
+       /* done setting up scanlines */
+       return totscanlines;
+}
+
+static int cmp_uv(float vec2a[2], float vec2b[2])
+{
+       return ((fabs(vec2a[0]-vec2b[0]) < 0.0001) && (fabs(vec2a[1]-vec2b[1]) < 0.0001)) ? 1:0;
+}
+       
+
+static int check_seam(ProjectPaintState *ps, int orig_face, int orig_i1_fidx, int orig_i2_fidx)
+{
+       LinkNode *node;
+       int face_index;
+       int i, i1, i2;
+       int i1_fidx = -1, i2_fidx = -1; /* indexi in face */
+       MFace *orig_mf, *mf;
+       MTFace *orig_tf, *tf;
+       
+       orig_mf = ps->dm_mface + orig_face;
+       orig_tf = ps->dm_mtface + orig_face;
+       
+       /* vert indicies from face vert order indicies */
+       i1 = (*(&orig_mf->v1 + orig_i1_fidx));
+       i2 = (*(&orig_mf->v1 + orig_i2_fidx));
+       
+       for (node = ps->projectVertFaces[i1]; node; node = node->next) {
+               face_index = (int)node->link;
+               if (face_index != orig_face) {
+                       mf = ps->dm_mface + face_index;
+                       
+                       /* We need to know the order of the verts in the adjacent face 
+                        * set the i1_fidx and i2_fidx to (0,1,2,3) */
+                       i = mf->v4 ? 3:2;
+                       do {
+                               if (i1 == (*(&mf->v1 + i))) {
+                                       i1_fidx = i;
+                               } else if (i2 == (*(&mf->v1 + i))) {
+                                       i2_fidx = i;
+                               }
+                               
+                       } while (i--);
+                       
+                       if (i2_fidx != -1) {
+                               /* This IS an adjacent face!, now lets check if the UVs are ok */
+                               
+                               tf = ps->dm_mtface + face_index;
+                               if (    cmp_uv(orig_tf->uv[orig_i1_fidx], tf->uv[i1_fidx]) &&
+                                               cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]) )
+                               {
+                                       // printf("SEAM (NONE)\n");
+                                       return 0;
+                                       
+                               } else {
+                                       // printf("SEAM (UV GAP)\n");
+                                       return 1;
+                               }
+                       }
+               }
+       }
+       // printf("SEAM (NO FACE)\n");
+       return 1;
+}
+
+static void project_face_seams_init(ProjectPaintState *ps, int face_index, int is_quad)
+{
+       if (is_quad) {
+               ps->projectFaceFlags[face_index] |= 
+                       (check_seam(ps, face_index, 0,1) ? PROJ_FACE_SEAM1 : 0) |
+                       (check_seam(ps, face_index, 1,2) ? PROJ_FACE_SEAM2 : 0) |
+                       (check_seam(ps, face_index, 2,3) ? PROJ_FACE_SEAM3 : 0) |
+                       (check_seam(ps, face_index, 3,0) ? PROJ_FACE_SEAM4 : 0);
+       } else {
+               ps->projectFaceFlags[face_index] |= 
+                       (check_seam(ps, face_index, 0,1) ? PROJ_FACE_SEAM1 : 0) |
+                       (check_seam(ps, face_index, 1,2) ? PROJ_FACE_SEAM2 : 0) |
+                       (check_seam(ps, face_index, 2,0) ? PROJ_FACE_SEAM3 : 0);
+       }
+}
+
+static float angleToLength(float angle)
+{
+       float x,y, fac;
+       
+       // Alredy accounted for
+       if (angle < 0.000001)
+               return 1.0;
+       
+       angle = (2.0*M_PI/360.0) * angle;
+       x = cos(angle);
+       y = sin(angle);
+       
+       // print "YX", x,y
+       // 0 d is hoz to the right.
+       // 90d is vert upward.
+       fac = 1.0/x;
+       x = x*fac;
+       y = y*fac;
+       return sqrt((x*x)+(y*y));
+}
+
+/* return zero if there is no area in the returned rectangle */
+static int uv_image_rect(float uv1[2], float uv2[2], float uv3[2], float uv4[2], int min_px[2], int max_px[2], int x_px, int y_px, int is_quad)
+{
+       float min_uv[2], max_uv[2]; /* UV bounds */
+       int i;
+       
+       INIT_MINMAX2(min_uv, max_uv);
+       
+       DO_MINMAX2(uv1, min_uv, max_uv);
+       DO_MINMAX2(uv2, min_uv, max_uv);
+       DO_MINMAX2(uv3, min_uv, max_uv);
+       if (is_quad)
+               DO_MINMAX2(uv4, min_uv, max_uv);
+       
+       min_px[0] = (int)(x_px * min_uv[0]);
+       min_px[1] = (int)(y_px * min_uv[1]);
+       
+       max_px[0] = (int)(x_px * max_uv[0]) +1;
+       max_px[1] = (int)(y_px * max_uv[1]) +1;
+       
+       /*printf("%d %d %d %d \n", min_px[0], min_px[1], max_px[0], max_px[1]);*/
+       CLAMP(min_px[0], 0, x_px);
+       CLAMP(max_px[0], 0, x_px);
+       
+       CLAMP(min_px[1], 0, y_px);
+       CLAMP(max_px[1], 0, y_px);
+       
+       /* face uses no UV area when quantized to pixels? */
+       return (min_px[0] == max_px[0] || min_px[1] == max_px[1]) ? 0 : 1;
+}
+
+/* takes a faces UV's and assigns outset coords to outset_uv */
+static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], float scaler, int x_px, int y_px, int is_quad)
+{
+       float a1,a2,a3,a4=0.0;
+       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];
+       
+       /* make UV's in pixel space so we can */
+       puv[0][0] = orig_uv[0][0] * x_px;
+       puv[0][1] = orig_uv[0][1] * y_px;
+       
+       puv[1][0] = orig_uv[1][0] * x_px;
+       puv[1][1] = orig_uv[1][1] * y_px;
+       
+       puv[2][0] = orig_uv[2][0] * x_px;
+       puv[2][1] = orig_uv[2][1] * y_px;
+       
+       if (is_quad) {
+               puv[3][0] = orig_uv[3][0] * x_px;
+               puv[3][1] = orig_uv[3][1] * y_px;
+       }
+       
+       /* face edge directions */
+       Vec2Subf(dir1, puv[1], puv[0]);
+       Vec2Subf(dir2, puv[2], puv[1]);
+       Normalize2(dir1);
+       Normalize2(dir2);
+       
+       if (is_quad) {
+               Vec2Subf(dir3, puv[3], puv[2]);
+               Vec2Subf(dir4, puv[0], puv[3]);
+               Normalize2(dir3);
+               Normalize2(dir4);
+       } else {
+               Vec2Subf(dir3, puv[0], puv[2]);
+               Normalize2(dir3);
+       }
+       
+       if (is_quad) {
+               a1 = NormalizedVecAngle2_2D(dir4, dir1);
+               a2 = NormalizedVecAngle2_2D(dir1, dir2);
+               a3 = NormalizedVecAngle2_2D(dir2, dir3);
+               a4 = NormalizedVecAngle2_2D(dir3, dir4);
+       } else {
+               a1 = NormalizedVecAngle2_2D(dir3, dir1);
+               a2 = NormalizedVecAngle2_2D(dir1, dir2);
+               a3 = NormalizedVecAngle2_2D(dir2, dir3);
+       }
+       
+       a1 = angleToLength(a1);
+       a2 = angleToLength(a2);
+       a3 = angleToLength(a3);
+       if (is_quad)
+               a4 = angleToLength(a4);
+       
+       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] /= x_px;
+               outset_uv[0][1] /= y_px;
+               
+               outset_uv[1][0] /= x_px;
+               outset_uv[1][1] /= y_px;
+               
+               outset_uv[2][0] /= x_px;
+               outset_uv[2][1] /= y_px;
+               
+               outset_uv[3][0] /= x_px;
+               outset_uv[3][1] /= y_px;
+       } 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] /= x_px;
+               outset_uv[0][1] /= y_px;
+               
+               outset_uv[1][0] /= x_px;
+               outset_uv[1][1] /= y_px;
+               
+               outset_uv[2][0] /= x_px;
+               outset_uv[2][1] /= y_px;
+       }
+}
+
+/* TODO - move to arithb.c */
+
+/* little sister we only need to know lambda */
+static float lambda_cp_line2(float p[2], float l1[2], float l2[2])
+{
+       float h[2],u[2];
+       Vec2Subf(u, l2, l1);
+       Vec2Subf(h, p, l1);
+       return(Inp2f(u,h)/Inp2f(u,u));
+}
+
+static screen_px_from_ortho(
+               ProjectPaintState *ps, float uv[2],
+               float v1co[3], float v2co[3], float v3co[3], /* Screenspace coords */
+               float uv1co[2], float uv2co[2], float uv3co[2],
+               float pixelScreenCo[4] )
+{
+       float w[3];
+       BarryCentricWeights2f(uv1co,uv2co,uv3co,uv,w);
+       pixelScreenCo[0] = v1co[0]*w[0] + v2co[0]*w[1] + v3co[0]*w[2];
+       pixelScreenCo[1] = v1co[1]*w[0] + v2co[1]*w[1] + v3co[1]*w[2];
+       pixelScreenCo[2] = v1co[2]*w[0] + v2co[2]*w[1] + v3co[2]*w[2];  
+}
+
+static screen_px_from_persp(
+               ProjectPaintState *ps, float uv[2],
+               float v1co[3], float v2co[3], float v3co[3], /* Worldspace coords */
+               float uv1co[2], float uv2co[2], float uv3co[2],
+               float pixelScreenCo[4])
+{
+       float w[3];
+       BarryCentricWeights2f(uv1co,uv2co,uv3co,uv,w);
+       pixelScreenCo[0] = v1co[0]*w[0] + v2co[0]*w[1] + v3co[0]*w[2];
+       pixelScreenCo[1] = v1co[1]*w[0] + v2co[1]*w[1] + v3co[1]*w[2];
+       pixelScreenCo[2] = v1co[2]*w[0] + v2co[2]*w[1] + v3co[2]*w[2];
+       pixelScreenCo[3] = 1.0;
+       
+       Mat4MulVec4fl(ps->projectMat, pixelScreenCo);
+       
+       // if( pixelScreenCo[3] > 0.001 ) { ??? TODO
+       /* screen space, not clamped */
+       pixelScreenCo[0] = (float)(curarea->winx/2.0)+(curarea->winx/2.0)*pixelScreenCo[0]/pixelScreenCo[3];    
+       pixelScreenCo[1] = (float)(curarea->winy/2.0)+(curarea->winy/2.0)*pixelScreenCo[1]/pixelScreenCo[3];
+       pixelScreenCo[2] = pixelScreenCo[2]/pixelScreenCo[3]; /* Use the depth for bucket point occlusion */
+}
+
+
+static void project_paint_bucket_init(ProjectPaintState *ps, int bucket_index);
+
+/* Only run this function once for new ProjectPixelClone's */
+#define pixel_size 4
+
+static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, float uv[2], int x, int y, int face_index, float pixelScreenCo[4])
+{
+       int bucket_index;
+       
+       // printf("adding px (%d %d), (%f %f)\n", x,y,uv[0],uv[1]);
+       
+       ProjectPixel *projPixel;
+       
+       bucket_index = project_paint_BucketOffsetSafe(ps, pixelScreenCo);
+       
+       /* even though it should be clamped, in some cases it can still run over */
+       if (bucket_index==-1)
+               return;
+       
+       /* Use viewMin2D to make (0,0) the bottom left of the bounds 
+        * Then this can be used to index the bucket array */
+       
+       /* Is this UV visible from the view? - raytrace */
+       if (ps->projectIsOcclude==0 || !project_bucket_point_occluded(ps, bucket_index, face_index, pixelScreenCo)) {
+               /* done with view3d_project_float inline */
+               if (ps->tool==PAINT_TOOL_CLONE) {
+                       float co[2];
+                       
+                       projPixel = (ProjectPixel *)BLI_memarena_alloc(ps->projectArena, sizeof(ProjectPixelClone));
+                       projPixel->pixel = (( char * ) ibuf->rect) + (( x + y * ibuf->x ) * pixel_size);
+                       VECCOPY2D(projPixel->projCo2D, pixelScreenCo);
+                       
+                       /* copy pixel color to backbuf */
+                       memcpy( &(((ProjectPixelClone *)projPixel)->backbuf), projPixel->pixel, pixel_size);
+                       //((ProjectPixelClone *)projPixel)->source = NULL; /* must be set later */
+                       
+                       
+                       /* Initialize clone pixels - note that this is a bit of a waste since some of these are being indirectly initialized :/ */
+                       /* TODO - possibly only run this for directly ativated buckets when cloning */
+                       Vec2Subf(co, projPixel->projCo2D, ps->cloneOfs);
+                               
+                       /* no need to initialize the bucket, we're only checking buckets faces and for this
+                        * the faces are alredy initialized in project_paint_delayed_face_init(...) */
+                       if (!screenco_pickcol(ps, bucket_index, co, ((ProjectPixelClone *)projPixel)->clonebuf)) {
+                               ((ProjectPixelClone *)projPixel)->clonebuf[3] = 0; /* zero alpha - ignore */
+                       }
+
+               } else {
+                       projPixel = (ProjectPixel *)BLI_memarena_alloc(ps->projectArena, sizeof(ProjectPixel));
+                       projPixel->pixel = (( char * ) ibuf->rect) + (( x + y * ibuf->x ) * pixel_size);
+                       VECCOPY2D(projPixel->projCo2D, pixelScreenCo);
+               }
+               
+               /* screenspace unclamped */
+               
+               
+               
+               
+#ifdef PROJ_DEBUG_PAINT
+               projPixel->pixel[1] = 0;
+#endif
+               projPixel->image_index = ps->image_index;
+               
+               BLI_linklist_prepend_arena(
+                       &ps->projectBuckets[ bucket_index ],
+                       projPixel,
+                       ps->projectArena
+               );
+       }
+}
+
+static void project_paint_face_init(ProjectPaintState *ps, int face_index, ImBuf *ibuf)
+{
+       /* Projection vars, to get the 3D locations into screen space  */
+       
+       MFace *mf = ps->dm_mface + face_index;
+       MTFace *tf = ps->dm_mtface + face_index;
+       
+       /* UV/pixel seeking data */
+       int x; /* Image X-Pixel */
+       int y;/* Image Y-Pixel */
+       float uv[2]; /* Image floating point UV - same as x,y but from 0.0-1.0 */
+       
+       int min_px[2], max_px[2]; /* UV Bounds converted to int's for pixel */
+       float *v1co, *v2co, *v3co; /* for convenience only, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
+       float *uv1co, *uv2co, *uv3co; /* for convenience only, these will be assigned to tf->uv[0],1,2 or tf->uv[0],2,3 */
+       float pixelScreenCo[4], pixelScreenCoXMin[4], pixelScreenCoXMax[4];
+       int i, j;
+       
+       /* scanlines since quads can have 2 triangles intersecting the same vertical location */
+#ifndef PROJ_DEBUG_NOSCANLINE 
+       ProjectScanline scanlines[2];
+       ProjectScanline *sc;
+       int totscanlines; /* can only be 1 or 2, oh well */
+#endif
+
+       if (!uv_image_rect(tf->uv[0], tf->uv[1], tf->uv[2], tf->uv[3], min_px, max_px, ibuf->x, ibuf->y, mf->v4))
+               return;
+       
+       /* detect UV seams so we can bleed */
+       if (ps->projectSeamBleed > 0.0)
+               project_face_seams_init(ps, face_index, mf->v4);
+       
+       for (y = min_px[1]; y < max_px[1]; y++) {
+               uv[1] = (((float)y)+0.5) / (float)ibuf->y; /* TODO - this is not pixel aligned correctly */
+
+#ifndef PROJ_DEBUG_NOSCANLINE 
+               totscanlines = project_face_scanline(scanlines, uv[1], tf->uv[0], tf->uv[1], tf->uv[2], mf->v4 ? tf->uv[3]:NULL);
+               
+               /* Loop over scanlines a bit silly since there can only be 1 or 2, but its easier then having tri/quad spesific functions */
+               for (j=0, sc=scanlines; j<totscanlines; j++, sc++) {
+                       
+                       min_px[0] = (int)((ibuf->x * sc->x_limits[0])+0.5);
+                       max_px[0] = (int)((ibuf->x * sc->x_limits[1])+0.5);
+                       CLAMP(min_px[0], 0, ibuf->x);
+                       CLAMP(max_px[0], 0, ibuf->x);
+                       
+                       uv1co = tf->uv[sc->v[0]];
+                       uv2co = tf->uv[sc->v[1]];
+                       uv3co = tf->uv[sc->v[2]];
+                       
+                       if (ps->projectIsOrtho) {
+                               v1co = ps->projectVertScreenCos[ (*(&mf->v1 + sc->v[0])) ];
+                               v2co = ps->projectVertScreenCos[ (*(&mf->v1 + sc->v[1])) ];
+                               v3co = ps->projectVertScreenCos[ (*(&mf->v1 + sc->v[2])) ];
+                               
+                               for (x = min_px[0]; x < max_px[0]; x++) {
+                                       uv[0] = (((float)x)+0.5) / (float)ibuf->x;
+                                       screen_px_from_ortho(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
+                                       project_paint_uvpixel_init(ps, ibuf, uv, x,y,face_index, pixelScreenCo);
+                               }
+                       } else {
+                               v1co = ps->dm_mvert[ (*(&mf->v1 + sc->v[0])) ].co;
+                               v2co = ps->dm_mvert[ (*(&mf->v1 + sc->v[1])) ].co;
+                               v3co = ps->dm_mvert[ (*(&mf->v1 + sc->v[2])) ].co;
+                               
+                               for (x = min_px[0]; x < max_px[0]; x++) {
+                                       uv[0] = (((float)x)+0.5) / (float)ibuf->x;
+                                       screen_px_from_persp(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
+                                       project_paint_uvpixel_init(ps, ibuf, uv, x,y,face_index, pixelScreenCo);
+                               }
+                       }
+               }
+#else  /* slow, non scanline method */
+               
+               /* mainly for debuggung scanline, use point-in-tri for every x/y test */
+               /* at the moment only works with ortho triangles */
+               uv1co = tf->uv[0];
+               uv2co = tf->uv[1];
+               uv3co = tf->uv[2];
+               
+               if (ps->projectIsOrtho) {
+                       v1co = ps->projectVertScreenCos[ mf->v1 ];
+                       v2co = ps->projectVertScreenCos[ mf->v2 ];
+                       v3co = ps->projectVertScreenCos[ mf->v3 ];
+                       
+                       for (x = min_px[0]; x < max_px[0]; x++) {
+                               uv[0] = (((float)x)+0.5) / (float)ibuf->x;
+                               if (IsectPT2Df(uv, uv1co, uv2co, uv3co)) {
+                                       screen_px_from_ortho(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
+                                       project_paint_uvpixel_init(ps, ibuf, uv, x,y,face_index, pixelScreenCo);
+                               }
+
+                       }
+               } else {
+                       /*
+                       v1co = ps->dm_mvert[ (*(&mf->v1 + sc->v[0])) ].co;
+                       v2co = ps->dm_mvert[ (*(&mf->v1 + sc->v[1])) ].co;
+                       v3co = ps->dm_mvert[ (*(&mf->v1 + sc->v[2])) ].co;
+                       
+                       for (x = min_px[0]; x < max_px[0]; x++) {
+                               uv[0] = (((float)x)+0.5) / (float)ibuf->x;
+                               screen_px_from_persp(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
+                               project_paint_uvpixel_init(ps, sc, ibuf, uv, x,y,face_index, pixelScreenCo);
+                       }
+                       */
+               }
+#endif
+       }
+
+       
+#ifndef PROJ_DEBUG_NOSCANLINE 
+       /* Pretty much a copy of above, except fill in seams if we have any */
+       if (ps->projectFaceFlags[face_index] & (PROJ_FACE_SEAM1|PROJ_FACE_SEAM2|PROJ_FACE_SEAM3|PROJ_FACE_SEAM4)) {
+               float outset_uv[4][2]; /* expanded UV's */
+               float insetCos[4][3]; /* expanded UV's */
+               float cent[3];
+               float *uv_seam_quads[4][4];
+               float *edge_verts[4][2];
+               float pixelScreenCo[3];
+               float fac;
+               int totuvseamquads = 0;
+               
+               if (ps->projectIsOrtho) {
+                       VECCOPY(insetCos[0], ps->projectVertScreenCos[ mf->v1 ]);
+                       VECCOPY(insetCos[1], ps->projectVertScreenCos[ mf->v2 ]);
+                       VECCOPY(insetCos[2], ps->projectVertScreenCos[ mf->v3 ]);
+                       if (mf->v4)
+                               VECCOPY(insetCos[3], ps->projectVertScreenCos[ mf->v4 ]);
+               } else {
+                       VECCOPY(insetCos[0], ps->dm_mvert[ mf->v1 ].co);
+                       VECCOPY(insetCos[1], ps->dm_mvert[ mf->v2 ].co);
+                       VECCOPY(insetCos[2], ps->dm_mvert[ mf->v3 ].co);
+                       if (mf->v4)
+                               VECCOPY(insetCos[3], ps->dm_mvert[ mf->v4 ].co);
+               }
+               
+                       
+               if (mf->v4) {
+                       cent[0] = (insetCos[0][0] + insetCos[1][0] + insetCos[2][0] + insetCos[3][0]) / 4.0;
+                       cent[1] = (insetCos[0][1] + insetCos[1][1] + insetCos[2][1] + insetCos[3][1]) / 4.0;
+                       cent[2] = (insetCos[0][2] + insetCos[1][2] + insetCos[2][2] + insetCos[3][2]) / 4.0;
+                       
+               } else {
+                       cent[0] = (insetCos[0][0] + insetCos[1][0] + insetCos[2][0]) / 3.0;
+                       cent[1] = (insetCos[0][1] + insetCos[1][1] + insetCos[2][1]) / 3.0;
+                       cent[2] = (insetCos[0][2] + insetCos[1][2] + insetCos[2][2]) / 3.0;
+               }
+               
+               VecSubf(insetCos[0], insetCos[0], cent);
+               VecSubf(insetCos[1], insetCos[1], cent);
+               VecSubf(insetCos[2], insetCos[2], cent);
+               if (mf->v4)
+                       VecSubf(insetCos[3], insetCos[3], cent);
+               
+               VecMulf(insetCos[0], 1.0 - 0.0001);
+               VecMulf(insetCos[1], 1.0 - 0.0001);
+               VecMulf(insetCos[2], 1.0 - 0.0001);
+               if (mf->v4)
+                       VecMulf(insetCos[3], 1.0 - 0.0001);
+               
+               VecAddf(insetCos[0], insetCos[0], cent);
+               VecAddf(insetCos[1], insetCos[1], cent);
+               VecAddf(insetCos[2], insetCos[2], cent);
+               if (mf->v4) 
+                       VecAddf(insetCos[3], insetCos[3], cent);
+               /* done with inset */
+               
+               uv_image_outset(tf->uv, outset_uv, ps->projectSeamBleed, ibuf->x, ibuf->y, mf->v4);
+               
+               if (ps->projectFaceFlags[face_index] & PROJ_FACE_SEAM1) {
+                       uv_seam_quads[totuvseamquads][0] = tf->uv[0];
+                       uv_seam_quads[totuvseamquads][1] = tf->uv[1];
+                       uv_seam_quads[totuvseamquads][2] = outset_uv[1];
+                       uv_seam_quads[totuvseamquads][3] = outset_uv[0];
+                       edge_verts[totuvseamquads][0] = insetCos[0]; //ps->projectVertScreenCos[ mf->v1 ];
+                       edge_verts[totuvseamquads][1] = insetCos[1]; //ps->projectVertScreenCos[ mf->v2 ];
+                       totuvseamquads++;
+               }
+               
+               if (ps->projectFaceFlags[face_index] & PROJ_FACE_SEAM2) {
+                       uv_seam_quads[totuvseamquads][0] = tf->uv[1];
+                       uv_seam_quads[totuvseamquads][1] = tf->uv[2];
+                       uv_seam_quads[totuvseamquads][2] = outset_uv[2];
+                       uv_seam_quads[totuvseamquads][3] = outset_uv[1];
+                       edge_verts[totuvseamquads][0] = insetCos[1]; //ps->projectVertScreenCos[ mf->v2 ];
+                       edge_verts[totuvseamquads][1] = insetCos[2]; //ps->projectVertScreenCos[ mf->v3 ];
+                       totuvseamquads++;
+               }
+               
+               if (mf->v4) {
+                       if (ps->projectFaceFlags[face_index] & PROJ_FACE_SEAM3) {
+                               uv_seam_quads[totuvseamquads][0] = tf->uv[2];
+                               uv_seam_quads[totuvseamquads][1] = tf->uv[3];
+                               uv_seam_quads[totuvseamquads][2] = outset_uv[3];
+                               uv_seam_quads[totuvseamquads][3] = outset_uv[2];
+                               edge_verts[totuvseamquads][0] = insetCos[2]; //ps->projectVertScreenCos[ mf->v3 ];
+                               edge_verts[totuvseamquads][1] = insetCos[3]; //ps->projectVertScreenCos[ mf->v4 ];
+                               totuvseamquads++;
+                       }
+                       if (ps->projectFaceFlags[face_index] & PROJ_FACE_SEAM4) {
+                               uv_seam_quads[totuvseamquads][0] = tf->uv[3];
+                               uv_seam_quads[totuvseamquads][1] = tf->uv[0];
+                               uv_seam_quads[totuvseamquads][2] = outset_uv[0];
+                               uv_seam_quads[totuvseamquads][3] = outset_uv[3];
+                               edge_verts[totuvseamquads][0] = insetCos[3]; //ps->projectVertScreenCos[ mf->v4 ];
+                               edge_verts[totuvseamquads][1] = insetCos[0]; //ps->projectVertScreenCos[ mf->v1 ];
+                               totuvseamquads++;
+                       }
+               } else {
+                       if (ps->projectFaceFlags[face_index] & PROJ_FACE_SEAM3) {
+                               uv_seam_quads[totuvseamquads][0] = tf->uv[2];
+                               uv_seam_quads[totuvseamquads][1] = tf->uv[0];
+                               uv_seam_quads[totuvseamquads][2] = outset_uv[0];
+                               uv_seam_quads[totuvseamquads][3] = outset_uv[2];
+                               edge_verts[totuvseamquads][0] = insetCos[2]; //ps->projectVertScreenCos[ mf->v3 ];
+                               edge_verts[totuvseamquads][1] = insetCos[0]; //ps->projectVertScreenCos[ mf->v1 ];
+                               totuvseamquads++;
+                       }
+               }
+               
+               for (i=0; i< totuvseamquads; i++) { /* loop over our seams */
+                       if (uv_image_rect(uv_seam_quads[i][0], uv_seam_quads[i][1], uv_seam_quads[i][2], uv_seam_quads[i][3], min_px, max_px, ibuf->x, ibuf->y, 1)) {
+                               
+                               for (y = min_px[1]; y < max_px[1]; y++) {
+                                       uv[1] = (((float)y)+0.5) / (float)ibuf->y;
+                                       
+                                       totscanlines = project_face_scanline(scanlines, uv[1], uv_seam_quads[i][0], uv_seam_quads[i][1], uv_seam_quads[i][2], uv_seam_quads[i][3]);
+                                       
+                                       /* Loop over scanlines a bit silly since there can only be 1 or 2, but its easier then having tri/quad spesific functions */
+                                       for (j=0, sc=scanlines; j<totscanlines; j++, sc++) {
+                                               
+                                               min_px[0] = (int)((ibuf->x * sc->x_limits[0])+0.5);
+                                               max_px[0] = (int)((ibuf->x * sc->x_limits[1])+0.5);
+                                               CLAMP(min_px[0], 0, ibuf->x);
+                                               CLAMP(max_px[0], 0, ibuf->x);
+                                               
+                                               for (x = min_px[0]; x < max_px[0]; x++) {
+                                                       uv[0] = (((float)x)+0.5) / (float)ibuf->x;
+                                                       
+                                                       /* We need to find the closest point allong the face edge,
+                                                        * getting the screen_px_from_*** wont work because our actual location
+                                                        * is not relevent, since we are outside the face, Use VecLerpf to find
+                                                        * our location on the side of the face's UV */
+                                                       /*
+                                                       if (ps->projectIsOrtho) screen_px_from_ortho(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
+                                                       else                                    screen_px_from_persp(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
+                                                       */
+                                                       
+                                                       /* Since this is a seam we need to work out where on the line this pixel is */
+                                                       fac = lambda_cp_line2(uv, uv_seam_quads[i][0], uv_seam_quads[i][1]);
+                                                       if (fac<0.0) {
+                                                               VECCOPY(pixelScreenCo, edge_verts[i][0]);
+                                                       } else if (fac>1.0) {
+                                                               VECCOPY(pixelScreenCo, edge_verts[i][1]);
+                                                       } else {
+                                                               VecLerpf(pixelScreenCo, edge_verts[i][0], edge_verts[i][1], fac);
+                                                       }
+                                                       
+                                                       if (!ps->projectIsOrtho) {
+                                                               pixelScreenCo[3] = 1.0;
+                                                               Mat4MulVec4fl(ps->projectMat, pixelScreenCo);
+                                                               pixelScreenCo[0] = (float)(curarea->winx/2.0)+(curarea->winx/2.0)*pixelScreenCo[0]/pixelScreenCo[3];    
+                                                               pixelScreenCo[1] = (float)(curarea->winy/2.0)+(curarea->winy/2.0)*pixelScreenCo[1]/pixelScreenCo[3];
+                                                               pixelScreenCo[2] = pixelScreenCo[2]/pixelScreenCo[3]; /* Use the depth for bucket point occlusion */
+                                                       }
+                                                       
+                                                       project_paint_uvpixel_init(ps, ibuf, uv, x, y, face_index, pixelScreenCo);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+#endif
+}
+
+
+
+
+
+/* takes floating point screenspace min/max and returns int min/max to be used as indicies for ps->projectBuckets, ps->projectBucketFlags */
+static void project_paint_rect(ProjectPaintState *ps, float min[2], float max[2], int bucket_min[2], int bucket_max[2])
+{
+       /* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */
+       bucket_min[0] = (int)(((float)(min[0] - ps->viewMin2D[0]) / ps->viewWidth) * ps->bucketsX) + 0.5; /* these offsets of 0.5 and 1.5 seem odd but they are correct */
+       bucket_min[1] = (int)(((float)(min[1] - ps->viewMin2D[1]) / ps->viewHeight) * ps->bucketsY) + 0.5;
+       
+       bucket_max[0] = (int)(((float)(max[0] - ps->viewMin2D[0]) / ps->viewWidth) * ps->bucketsX) + 1.5;
+       bucket_max[1] = (int)(((float)(max[1] - ps->viewMin2D[1]) / ps->viewHeight) * ps->bucketsY) + 1.5;      
+       
+       /* incase the rect is outside the mesh 2d bounds */
+       CLAMP(bucket_min[0], 0, ps->bucketsX);
+       CLAMP(bucket_min[1], 0, ps->bucketsY);
+       
+       CLAMP(bucket_max[0], 0, ps->bucketsX);
+       CLAMP(bucket_max[1], 0, ps->bucketsY);
+}
+
+static void project_bucket_bounds(ProjectPaintState *ps, int bucket_x, int bucket_y, float bucket_bounds[4])
+{
+       bucket_bounds[ PROJ_BUCKET_LEFT ] =             ps->viewMin2D[0]+((bucket_x)*(ps->viewWidth / ps->bucketsX));           /* left */
+       bucket_bounds[ PROJ_BUCKET_RIGHT ] =    ps->viewMin2D[0]+((bucket_x+1)*(ps->viewWidth / ps->bucketsX)); /* right */
+       
+       bucket_bounds[ PROJ_BUCKET_BOTTOM ] =   ps->viewMin2D[1]+((bucket_y)*(ps->viewHeight / ps->bucketsY));          /* bottom */
+       bucket_bounds[ PROJ_BUCKET_TOP ] =              ps->viewMin2D[1]+((bucket_y+1)*(ps->viewHeight  / ps->bucketsY));       /* top */
+}
+
+static void project_paint_bucket_init(ProjectPaintState *ps, int bucket_index)
+{
+       LinkNode *node;
+       int face_index;
+       ImBuf *ibuf;
+       MTFace *tf;
+       
+       /*printf("\tinit bucket %d\n", bucket_index);*/
+       
+       ps->projectBucketFlags[bucket_index] |= PROJ_BUCKET_INIT; 
+       
+       if ((node = ps->projectFaces[bucket_index])) {
+               do {
+                       face_index = (int)node->link;
+                       /* Have we initialized this face in another bucket? */
+                       if ((ps->projectFaceFlags[face_index] & PROJ_FACE_INIT)==0) {
+                               
+                               ps->projectFaceFlags[face_index] |= PROJ_FACE_INIT;
+                               
+                               tf = ps->dm_mtface+face_index;
+                               ibuf = BKE_image_get_ibuf((Image *)tf->tpage, NULL); /* TODO - this may be slow */
+                               
+                               project_paint_face_init(ps, face_index, ibuf);
+                       }
+                       node = node->next;
+               } while (node);
+       }
+}
+
+
+/* We want to know if a bucket and a face overlap in screenspace
+ * 
+ * Note, if this ever returns false positives its not that bad, since a face in the bounding area will have its pixels
+ * calculated when it might not be needed later, (at the moment at least)
+ * obviously it shouldnt have bugs though */
+
+static int project_bucket_face_isect(ProjectPaintState *ps, float min[2], float max[2], int bucket_x, int bucket_y, int bucket_index, MFace *mf)
+{
+       /* TODO - replace this with a tricker method that uses sideofline for all projectVertScreenCos's edges against the closest bucket corner */
+       float bucket_bounds[4];
+       float p1[2], p2[2], p3[2], p4[2];
+       float *v, *v1,*v2,*v3,*v4;
+       int i;
+       
+       project_bucket_bounds(ps, bucket_x, bucket_y, bucket_bounds);
+       
+       /* Is one of the faces verts in the bucket bounds? */
+       
+       i = mf->v4 ? 3:2;
+       do {
+               v = ps->projectVertScreenCos[ (*(&mf->v1 + i)) ];
+               
+               if ((v[0] > bucket_bounds[PROJ_BUCKET_LEFT]) &&
+                       (v[0] < bucket_bounds[PROJ_BUCKET_RIGHT]) &&
+                       (v[1] > bucket_bounds[PROJ_BUCKET_BOTTOM]) &&
+                       (v[1] < bucket_bounds[PROJ_BUCKET_TOP]) )
+               {
+                       return 1;
+               }
+       } while (i--);
+               
+       v1 = ps->projectVertScreenCos[mf->v1];
+       v2 = ps->projectVertScreenCos[mf->v2];
+       v3 = ps->projectVertScreenCos[mf->v3];
+       if (mf->v4) {
+               v4 = ps->projectVertScreenCos[mf->v4];
+       }
+       
+       p1[0] = bucket_bounds[PROJ_BUCKET_LEFT];        p1[1] = bucket_bounds[PROJ_BUCKET_BOTTOM];
+       p2[0] = bucket_bounds[PROJ_BUCKET_LEFT];        p2[1] = bucket_bounds[PROJ_BUCKET_TOP];
+       p3[0] = bucket_bounds[PROJ_BUCKET_RIGHT];       p3[1] = bucket_bounds[PROJ_BUCKET_TOP];
+       p4[0] = bucket_bounds[PROJ_BUCKET_RIGHT];       p4[1] = bucket_bounds[PROJ_BUCKET_BOTTOM];
+               
+       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) ||
+                       /* 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))
+               ) {
+                       return 1;
+               }
+       } else {
+               if(     IsectPT2Df(p1, v1, v2, v3) || IsectPT2Df(p2, v1, v2, v3) || IsectPT2Df(p3, v1, v2, v3) || IsectPT2Df(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))
+               ) {
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static void project_paint_delayed_face_init(ProjectPaintState *ps, MFace *mf, MTFace *tf, int face_index)
+{
+       float min[2], max[2];
+       int bucket_min[2], bucket_max[2]; /* for  ps->projectBuckets indexing */
+       int i, a, bucket_x, bucket_y, bucket_index;
+
+       INIT_MINMAX2(min,max);
+       
+       i = mf->v4 ? 3:2;
+       do {
+               a = (*(&mf->v1 + i)); /* vertex index */
+               
+               DO_MINMAX2(ps->projectVertScreenCos[ a ], min, max);
+               
+               /* add face user if we have bleed enabled, set the UV seam flags later */
+               if (ps->projectSeamBleed > 0.0) {
+                       BLI_linklist_prepend_arena(
+                               &ps->projectVertFaces[ a ],
+                               (void *)face_index, /* cast to a pointer to shut up the compiler */
+                               ps->projectArena
+                       );
+               }
+       } while (i--);
+       
+       project_paint_rect(ps, min, max, bucket_min, bucket_max);
+       
+       for (bucket_y = bucket_min[1]; bucket_y < bucket_max[1]; bucket_y++) {
+               for (bucket_x = bucket_min[0]; bucket_x < bucket_max[0]; bucket_x++) {
+                       
+                       bucket_index = bucket_x + (bucket_y * ps->bucketsX);
+                       
+                       if (project_bucket_face_isect(ps, min, max, bucket_x, bucket_y, bucket_index, mf)) {
+                               BLI_linklist_prepend_arena(
+                                       &ps->projectFaces[ bucket_index ],
+                                       (void *)face_index, /* cast to a pointer to shut up the compiler */
+                                       ps->projectArena
+                               );
+                       }
+               }
+       }
+}
+
+static void project_paint_begin( ProjectPaintState *ps, short mval[2])
+{      
+       /* Viewport vars */
+       float mat[3][3];
+       float f_no[3];
+       
+       float projCo[4];
+       float (*projScreenCo)[3];
+       float projMargin;
+       /* Image Vars - keep track of images we have used */
+       LinkNode *image_LinkList = NULL;
+       LinkNode *node;
+       
+       Image *tpage_last = NULL;
+       ImBuf *ibuf = NULL;
+       
+       /* Face vars */
+       MFace *mf;
+       MTFace *tf;
+       
+       int a, i; /* generic looping vars */
+       
+       /* memory sized to add to arena size */
+       int tot_bucketMem=0;
+       int tot_faceFlagMem=0;
+       int tot_faceListMem=0;
+       int tot_bucketFlagMem=0;
+       int tot_bucketVertFacesMem=0;
+
+       /* ---- end defines ---- */
+       
+       /* paint onto the derived mesh
+        * note get_viewedit_datamask checks for paint mode and will always give UVs */
+       ps->dm = mesh_get_derived_final(ps->ob, get_viewedit_datamask());
+       
+       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 );
+       
+       ps->dm_totvert = ps->dm->getNumVerts( ps->dm );
+       ps->dm_totface = ps->dm->getNumFaces( ps->dm );
+       
+       ps->bucketsX = PROJ_BUCKET_DIV;
+       ps->bucketsY = PROJ_BUCKET_DIV;
+       
+       ps->image_index = -1;
+       
+       ps->viewDir[0] = 0.0;
+       ps->viewDir[1] = 0.0;
+       ps->viewDir[2] = 1.0;
+       
+       view3d_get_object_project_mat(curarea, ps->ob, ps->projectMat, ps->viewMat);
+       
+       tot_bucketMem =                         sizeof(LinkNode *) * ps->bucketsX * ps->bucketsY;
+       tot_faceListMem =                       sizeof(LinkNode *) * ps->bucketsX * ps->bucketsY;
+       tot_faceFlagMem =                       sizeof(char) * ps->dm_totface;
+       tot_bucketFlagMem =                     sizeof(char) * ps->bucketsX * ps->bucketsY;
+       if (ps->projectSeamBleed > 0.0) /* UV Seams for bleeding */
+               tot_bucketVertFacesMem =        sizeof(LinkNode *) * ps->dm_totvert;
+       
+
+       ps->projectArena =
+               BLI_memarena_new(       tot_bucketMem +
+                                                       tot_faceListMem +
+                                                       tot_faceFlagMem +
+                                                       tot_bucketVertFacesMem + (1<<16));
+       
+       ps->projectBuckets = (LinkNode **)BLI_memarena_alloc( ps->projectArena, tot_bucketMem);
+       ps->projectFaces= (LinkNode **)BLI_memarena_alloc( ps->projectArena, tot_faceListMem);
+       ps->projectFaceFlags = (char *)BLI_memarena_alloc( ps->projectArena, tot_faceFlagMem);
+       ps->projectBucketFlags= (char *)BLI_memarena_alloc( ps->projectArena, tot_bucketFlagMem);
+       if (ps->projectSeamBleed > 0.0)
+               ps->projectVertFaces= (LinkNode **)BLI_memarena_alloc( ps->projectArena, tot_bucketVertFacesMem);
+       
+       memset(ps->projectBuckets,              0, tot_bucketMem);
+       memset(ps->projectFaces,                0, tot_faceListMem);
+       memset(ps->projectFaceFlags,    0, tot_faceFlagMem);
+       memset(ps->projectBucketFlags,  0, tot_bucketFlagMem);
+       if (ps->projectSeamBleed > 0.0)
+               memset(ps->projectVertFaces,    0, tot_bucketVertFacesMem);
+       
+       Mat4Invert(ps->ob->imat, ps->ob->obmat);
+       
+       Mat3CpyMat4(mat, G.vd->viewinv);
+       Mat3MulVecfl(mat, ps->viewDir);
+       Mat3CpyMat4(mat, ps->ob->imat);
+       Mat3MulVecfl(mat, ps->viewDir);
+       
+       /* calculate vert screen coords */
+       ps->projectVertScreenCos = BLI_memarena_alloc( ps->projectArena, sizeof(float) * ps->dm_totvert * 3);
+       projScreenCo = ps->projectVertScreenCos;
+       
+       /* TODO - check cameras mode too */
+       if (G.vd->persp == V3D_ORTHO) {
+               ps->projectIsOrtho = 1;
+       }
+       
+       INIT_MINMAX2(ps->viewMin2D, ps->viewMax2D);
+       
+       for(a=0; a < ps->dm_totvert; a++, projScreenCo++) {
+               VECCOPY(projCo, ps->dm_mvert[a].co);            
+               
+               projCo[3] = 1.0;
+               Mat4MulVec4fl(ps->projectMat, projCo);
+               
+               if( projCo[3] > 0.001 ) {
+                       /* screen space, not clamped */
+                       (*projScreenCo)[0] = (float)(curarea->winx/2.0)+(curarea->winx/2.0)*projCo[0]/projCo[3];        
+                       (*projScreenCo)[1] = (float)(curarea->winy/2.0)+(curarea->winy/2.0)*projCo[1]/projCo[3];
+                       (*projScreenCo)[2] = projCo[2]/projCo[3]; /* Use the depth for bucket point occlusion */
+                       DO_MINMAX2((*projScreenCo), ps->viewMin2D, ps->viewMax2D);
+               } else {
+                       /* TODO - deal with cases where 1 side of a face goes behind the view ? */
+                       (*projScreenCo)[0] = (*projScreenCo)[1] = MAXFLOAT;
+               }
+       }
+       
+       /* setup clone offset */
+       if (ps->tool == PAINT_TOOL_CLONE) {
+               float *curs= give_cursor();
+               VECCOPY(projCo, curs); /* TODO - what if were in local view? - get some better way */
+               Mat4MulVec4fl(ps->ob->imat, projCo);
+               projCo[3] = 1.0;
+               Mat4MulVec4fl(ps->projectMat, projCo);
+               ps->cloneOfs[0] = mval[0] - ((float)(curarea->winx/2.0)+(curarea->winx/2.0)*projCo[0]/projCo[3]);
+               ps->cloneOfs[1] = mval[1] - ((float)(curarea->winy/2.0)+(curarea->winy/2.0)*projCo[1]/projCo[3]);
+               
+               // printf("%f %f   %f %f %f\n", ps->cloneOfs[0], ps->cloneOfs[1], curs[0], curs[1], curs[2]);
+               
+       }
+       
+       /* If this border is not added we get artifacts for faces that
+        * have a paralelle edge and at the bounds of the the 2D projected verts eg
+        * - a simgle screen aligned quad */
+       projMargin = (ps->viewMax2D[0] - ps->viewMin2D[0]) * 0.000001;
+       ps->viewMax2D[0] += projMargin;
+       ps->viewMin2D[0] -= projMargin;
+       projMargin = (ps->viewMax2D[1] - ps->viewMin2D[1]) * 0.000001;
+       ps->viewMax2D[1] += projMargin;
+       ps->viewMin2D[1] -= projMargin;
+       
+       
+       /* only for convenience */
+       ps->viewWidth  = ps->viewMax2D[0] - ps->viewMin2D[0];
+       ps->viewHeight = ps->viewMax2D[1] - ps->viewMin2D[1];
+       
+       for( a = 0, tf = ps->dm_mtface, mf = ps->dm_mface; a < ps->dm_totface; mf++, tf++, a++ ) {
+               if (tf->tpage && ((G.f & G_FACESELECT)==0 || mf->flag & ME_FACE_SEL)) {
+                       
+                       if (ps->projectIsBackfaceCull) {
+                               /* TODO - we dont really need the normal, just the direction, save a sqrt? */
+                               if (mf->v4)     CalcNormFloat4(ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, f_no);
+                               else            CalcNormFloat(ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, f_no);
+                               
+                               if (Inpf(f_no, ps->viewDir) < 0) {
+                                       continue;
+                               }
+                       }
+                       
+                       if (tpage_last != tf->tpage) {
+                               ibuf= BKE_image_get_ibuf((Image *)tf->tpage, NULL);
+                               
+                               if (ibuf) {
+                                       /* TODO - replace this with not yet existant BLI_linklist_index function */
+                                       for     (
+                                               node=image_LinkList, ps->image_index=0;
+                                               node && node->link != tf->tpage ;
+                                               node = node->next, ps->image_index++
+                                       ) {}
+                                       
+                                       if (node==NULL) { /* MemArena dosnt have an append func */
+                                               BLI_linklist_append(&image_LinkList, tf->tpage);
+                                               ps->projectImageTotal = ps->image_index+1;
+                                       }
+                               }
+                               
+                               tpage_last = tf->tpage;
+                       }
+                       
+                       if (ibuf) {
+                               /* Initialize the faces screen pixels */
+                               /* Add this to a list to initialize later */
+                               project_paint_delayed_face_init(ps, mf, tf, a);
+                       }
+               }
+       }
+       
+       /* build an array of images we use*/
+       ps->projectImages = BLI_memarena_alloc( ps->projectArena, sizeof(Image *) * ps->projectImageTotal);
+       
+       for (node= image_LinkList, i=0; node; node= node->next, i++) {
+               
+               ps->projectImages[i] = node->link;
+               ps->projectImages[i]->id.flag &= ~LIB_DOIT;
+               // printf("'%s' %d\n", ps->projectImages[i]->id.name+2, i);
+       }
+       /* we have built the array, discard the linked list */
+       BLI_linklist_free(image_LinkList, NULL);
+}
+
+static void project_paint_end( ProjectPaintState *ps )
+{
+       BLI_memarena_free(ps->projectArena);
+       ps->dm->release(ps->dm);
+}
+
+
 /* external functions */
 
 /* 1= an undo, -1 is a redo. */
@@ -569,6 +2038,8 @@ static void imapaint_convert_brushco(ImBuf *ibufb, float *pos, int *ipos)
        ipos[1]= (int)(pos[1] - ibufb->y/2);
 }
 
+/* dosnt run for projection painting
+ * only the old style painting in the 3d view */
 static int imapaint_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *pos)
 {
        ImagePaintState *s= ((ImagePaintState*)state);
@@ -710,6 +2181,232 @@ static int imapaint_paint_sub_stroke(ImagePaintState *s, BrushPainter *painter,
        else return 0;
 }
 
+static float Vec2Lenf_nosqrt(float *v1, float *v2)
+{
+       float x, y;
+
+       x = v1[0]-v2[0];
+       y = v1[1]-v2[1];
+       return x*x+y*y;
+}
+
+static float Vec2Lenf_nosqrt_other(float *v1, float v2_1, float v2_2)
+{
+       float x, y;
+
+       x = v1[0]-v2_1;
+       y = v1[1]-v2_2;
+       return x*x+y*y;
+}
+
+/* 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 */
+static int project_bucket_circle_isect(ProjectPaintState *ps, int bucket_x, int bucket_y, float cent[2], float radius_squared)
+{
+       float bucket_bounds[4];
+       //return 1;
+       
+       project_bucket_bounds(ps, bucket_x, bucket_y, bucket_bounds);
+       
+       // printf("%d %d - %f %f %f %f - %f %f \n", bucket_x, bucket_y, bucket_bounds[0], bucket_bounds[1], bucket_bounds[2], bucket_bounds[3], cent[0], cent[1]);
+
+       /* first check if we are INSIDE the bucket */
+       /* if ( bucket_bounds[PROJ_BUCKET_LEFT] <=      cent[0] &&
+                       bucket_bounds[PROJ_BUCKET_RIGHT] >=     cent[0] &&
+                       bucket_bounds[PROJ_BUCKET_BOTTOM] <=    cent[1] &&
+                       bucket_bounds[PROJ_BUCKET_TOP] >=       cent[1] )
+       {
+               return 1;
+       }*/
+       
+       /* Would normally to a simple intersection test, however we know the bounds of these 2 alredy 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 */
+       if (  ( bucket_bounds[PROJ_BUCKET_LEFT] <=              cent[0] &&
+                       bucket_bounds[PROJ_BUCKET_RIGHT] >=             cent[0]) ||
+                 (     bucket_bounds[PROJ_BUCKET_BOTTOM] <=    cent[1] &&
+                       bucket_bounds[PROJ_BUCKET_TOP] >=               cent[1]) )
+       {
+               return 1;
+       }
+        
+       /* out of bounds left */
+       if (cent[0] < bucket_bounds[PROJ_BUCKET_LEFT]) {
+               /* lower left out of radius test */
+               if (cent[1] < bucket_bounds[PROJ_BUCKET_BOTTOM]) {
+                       return (Vec2Lenf_nosqrt_other(cent, bucket_bounds[PROJ_BUCKET_LEFT], bucket_bounds[PROJ_BUCKET_BOTTOM]) < radius_squared) ? 1 : 0;
+               } 
+               /* top left test */
+               else if (cent[1] > bucket_bounds[PROJ_BUCKET_TOP]) {
+                       return (Vec2Lenf_nosqrt_other(cent, bucket_bounds[PROJ_BUCKET_LEFT], bucket_bounds[PROJ_BUCKET_TOP]) < radius_squared) ? 1 : 0;
+               }
+       }
+       else if (cent[0] > bucket_bounds[PROJ_BUCKET_RIGHT]) {
+               /* lower right out of radius test */
+               if (cent[1] < bucket_bounds[PROJ_BUCKET_BOTTOM]) {
+                       return (Vec2Lenf_nosqrt_other(cent, bucket_bounds[PROJ_BUCKET_RIGHT], bucket_bounds[PROJ_BUCKET_BOTTOM]) < radius_squared) ? 1 : 0;
+               } 
+               /* top right test */
+               else if (cent[1] > bucket_bounds[PROJ_BUCKET_TOP]) {
+                       return (Vec2Lenf_nosqrt_other(cent, bucket_bounds[PROJ_BUCKET_RIGHT], bucket_bounds[PROJ_BUCKET_TOP]) < radius_squared) ? 1 : 0;
+               }
+       }
+       
+       return 0;
+}
+
+static int imapaint_paint_sub_stroke_project(ProjectPaintState *ps, BrushPainter *painter, short mval[2], double time, int update, float pressure)
+{
+       /* TODO - texpaint option : is there any use in projection painting from the image window??? - could be interesting */
+       /* TODO - floating point images */
+       //bucketWidth = ps->viewWidth/ps->bucketsX;
+       //bucketHeight = ps->viewHeight/ps->bucketsY;
+
+       LinkNode *node;
+       float mval_f[2];
+       ProjectPixel *projPixel;
+       int redraw = 0;
+       int last_index = -1;
+       float rgba[4], alpha, dist, dist_nosqrt;
+       float brush_size_sqared;
+       float min[2], max[2]; /* brush bounds in screenspace */
+       int bucket_min[2], bucket_max[2]; /* brush bounds in bucket grid space */
+       int bucket_index;
+       int a;
+       
+       int bucket_x, bucket_y;
+       
+       mval_f[0] = mval[0]; mval_f[1] = mval[1]; 
+       
+       min[0] = mval_f[0] - (ps->brush->size/2);
+       min[1] = mval_f[1] - (ps->brush->size/2);
+       
+       max[0] = mval_f[0] + (ps->brush->size/2);
+       max[1] = mval_f[1] + (ps->brush->size/2);
+       
+       /* offset to make this a valid bucket index */
+       project_paint_rect(ps, min, max, bucket_min, bucket_max);
+       
+       /* mouse outside the model areas? */
+       if (bucket_min[0]==bucket_max[0] || bucket_min[1]==bucket_max[1]) {
+               return 0;
+       }
+       
+       /* 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", bucket_min[0], bucket_min[1], bucket_max[0], bucket_max[1]); */
+       
+       /* If there is ever problems with getting the bounds for the brush, set the bounds to include all */
+       /*bucket_min[0] = 0; bucket_min[1] = 0; bucket_max[0] = ps->bucketsX; bucket_max[1] = ps->bucketsY;*/
+       
+       /* no clamping needed, dont use screen bounds, use vert bounds  */
+       
+       for (bucket_y = bucket_min[1]; bucket_y < bucket_max[1]; bucket_y++) {
+               for (bucket_x = bucket_min[0]; bucket_x < bucket_max[0]; bucket_x++) {
+                       
+                       if (project_bucket_circle_isect(ps, bucket_x, bucket_y, mval_f, brush_size_sqared)) {
+                               
+                               bucket_index = bucket_x + (bucket_y * ps->bucketsX);
+                               
+                               /* Check this bucket and its faces are initialized */
+                               if (ps->projectBucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
+                                       /* This bucket may hold some uninitialized faces, initialize it */
+                                       project_paint_bucket_init(ps, bucket_index);
+                               }
+                               
+                               /* TODO - we may want to init clone data in a seperate to project_paint_bucket_init
+                                * so we dont go overboard and init too many clone pixels  */
+
+                               if ((node = ps->projectBuckets[bucket_index])) {
+                               
+                                       do {
+                                               projPixel = (ProjectPixel *)node->link;
+#ifdef PROJ_DEBUG_PAINT
+                                               projPixel->pixel[0] = 0; // use for checking if the starting radius is too big
+#endif
+                                               
+                                               /*dist = Vec2Lenf(projPixel->projCo2D, mval_f);*/ /* correct but uses a sqrt */
+                                               dist_nosqrt = Vec2Lenf_nosqrt(projPixel->projCo2D, mval_f);
+                                               
+                                               /*if (dist < s->brush->size) {*/ /* correct but uses a sqrt */
+                                               if (dist_nosqrt < brush_size_sqared) {
+                                                       
+                                                       dist = (float)sqrt(dist_nosqrt);
+                                                       
+                                                       if (ps->tool==PAINT_TOOL_CLONE) { //&& ((ProjectPixelClone*)projPixel)->source )  {
+                                                               
+                                                               alpha = brush_sample_falloff(ps->brush, dist);
+                                                               
+                                                               if (((char *)((ProjectPixelClone*)projPixel)->clonebuf)[3]) {
+                                                                       projPixel->pixel[0] = FTOCHAR((((((char *)((ProjectPixelClone*)projPixel)->clonebuf)[0]/255.0) * alpha) + (((projPixel->pixel[0])/255.0)*(1.0-alpha))));
+                                                                       projPixel->pixel[1] = FTOCHAR((((((char *)((ProjectPixelClone*)projPixel)->clonebuf)[1]/255.0) * alpha) + (((projPixel->pixel[1])/255.0)*(1.0-alpha))));
+                                                                       projPixel->pixel[2] = FTOCHAR((((((char *)((ProjectPixelClone*)projPixel)->clonebuf)[2]/255.0) * alpha) + (((projPixel->pixel[2])/255.0)*(1.0-alpha))));
+                                                               }
+                                                               
+#if 0
+                                                               if (alpha <= 0.0) {
+                                                                       /* do nothing */
+                                                               } else {
+                                                                       if (alpha >= 1.0) {
+                                                                               projPixel->pixel[0] = FTOCHAR(rgba[0]*ps->brush->rgb[0]);
+                                                                               projPixel->pixel[1] = FTOCHAR(rgba[1]*ps->brush->rgb[1]);
+                                                                               projPixel->pixel[2] = FTOCHAR(rgba[2]*ps->brush->rgb[2]);
+                                                                       } else {
+                                                                               projPixel->pixel[0] = FTOCHAR(((rgba[0]*ps->brush->rgb[0])*alpha) + (((projPixel->pixel[0])/255.0)*(1.0-alpha)));
+                                                                               projPixel->pixel[1] = FTOCHAR(((rgba[1]*ps->brush->rgb[1])*alpha) + (((projPixel->pixel[1])/255.0)*(1.0-alpha)));
+                                                                               projPixel->pixel[2] = FTOCHAR(((rgba[2]*ps->brush->rgb[2])*alpha) + (((projPixel->pixel[2])/255.0)*(1.0-alpha)));
+                                                                       }
+                                                               } 
+#endif
+                                                       } else {
+                                                               brush_sample_tex(ps->brush, projPixel->projCo2D, rgba);
+                                                               alpha = rgba[3]*brush_sample_falloff(ps->brush, dist);
+                                                               
+                                                               if (alpha <= 0.0) {
+                                                                       /* do nothing */
+                                                               } else {
+                                                                       if (alpha >= 1.0) {
+                                                                               projPixel->pixel[0] = FTOCHAR(rgba[0]*ps->brush->rgb[0]);
+                                                                               projPixel->pixel[1] = FTOCHAR(rgba[1]*ps->brush->rgb[1]);
+                                                                               projPixel->pixel[2] = FTOCHAR(rgba[2]*ps->brush->rgb[2]);
+                                                                       } else {
+                                                                               projPixel->pixel[0] = FTOCHAR(((rgba[0]*ps->brush->rgb[0])*alpha) + (((projPixel->pixel[0])/255.0)*(1.0-alpha)));
+                                                                               projPixel->pixel[1] = FTOCHAR(((rgba[1]*ps->brush->rgb[1])*alpha) + (((projPixel->pixel[1])/255.0)*(1.0-alpha)));
+                                                                               projPixel->pixel[2] = FTOCHAR(((rgba[2]*ps->brush->rgb[2])*alpha) + (((projPixel->pixel[2])/255.0)*(1.0-alpha)));
+                                                                       }
+                                                               } 
+                                                       }
+                                                       
+                                                       if (last_index != projPixel->image_index) {
+                                                               last_index = projPixel->image_index;
+                                                               ps->projectImages[last_index]->id.flag |= LIB_DOIT;
+                                                       }
+                                                       
+                                               }
+                                               
+                                               node = node->next;
+                                       } while (node);
+                               }
+                       }
+               }
+       }
+
+       /* Loop over all images on this mesh and update any we have touched */
+       for (a=0; a < ps->projectImageTotal; a++) {
+               Image *ima = ps->projectImages[a];
+               if (ima->id.flag & LIB_DOIT) {
+                       imapaint_image_update(ima, BKE_image_get_ibuf(ima, NULL), 1 /*texpaint*/ );
+                       redraw = 1;
+                       
+                       ima->id.flag &= ~LIB_DOIT; /* clear for reuse */
+               }
+       }
+       
+       return redraw;
+}
+
+
 static void imapaint_paint_stroke(ImagePaintState *s, BrushPainter *painter, short texpaint, short *prevmval, short *mval, double time, float pressure)
 {
        Image *newimage = NULL;
@@ -790,28 +2487,60 @@ static void imapaint_paint_stroke(ImagePaintState *s, BrushPainter *painter, sho
        }
 }
 
+static void imapaint_paint_stroke_project(ProjectPaintState *ps, BrushPainter *painter, short *prevmval, short *mval, double time, float pressure)
+{
+       int redraw = 0;
+       
+       /* TODO - support more brush operations, airbrush etc */
+       {
+               redraw |= imapaint_paint_sub_stroke_project(ps, painter, mval, time, 1, pressure);
+       }
+       
+       if (redraw) {
+               imapaint_redraw(0, 1/*texpaint*/, NULL);
+               imapaint_clear_partial_redraw();
+       }
+}
+
 void imagepaint_paint(short mousebutton, short texpaint)
 {
        ImagePaintState s;
+       ProjectPaintState ps;
        BrushPainter *painter;
        ToolSettings *settings= G.scene->toolsettings;
-       short prevmval[2], mval[2];
+       short prevmval[2], mval[2], project = 0;
        double time;
        float pressure;
 
        if(!settings->imapaint.brush)
                return;
-
+       
+       project = texpaint;
+       
+       
+       if (G.qual & LR_CTRLKEY) {
+               mouse_cursor();
+               return;
+       }
+       
        /* initialize state */
        memset(&s, 0, sizeof(s));
+       memset(&ps, 0, sizeof(ps));
+       
        s.brush = settings->imapaint.brush;
        s.tool = settings->imapaint.tool;
-       if(texpaint && (s.tool == PAINT_TOOL_CLONE))
+       if(texpaint && (project==0) && (s.tool == PAINT_TOOL_CLONE))
                s.tool = PAINT_TOOL_DRAW;
        s.blend = s.brush->blend;
-
+       
+       if (project) {
+               ps.brush = s.brush;
+               ps.tool = s.tool;
+               ps.blend = s.blend;
+       }
+       
        if(texpaint) {
-               s.ob = OBACT;
+               ps.ob = s.ob = OBACT;
                if (!s.ob || !(s.ob->lay & G.vd->lay)) return;
                s.me = get_mesh(s.ob);
                if (!s.me) return;
@@ -844,13 +2573,20 @@ void imagepaint_paint(short mousebutton, short texpaint)
        time= PIL_check_seconds_timer();
        prevmval[0]= mval[0];
        prevmval[1]= mval[1];
-
-       /* special exception here for too high pressure values on first touch in
-          windows for some tablets */
-    if (!((s.brush->flag & (BRUSH_ALPHA_PRESSURE|BRUSH_SIZE_PRESSURE|
-               BRUSH_SPACING_PRESSURE|BRUSH_RAD_PRESSURE)) && (get_activedevice() != 0) && (pressure >= 0.99f)))
-               imapaint_paint_stroke(&s, painter, texpaint, prevmval, mval, time, pressure);
-
+       
+       if (project) {
+               /* setup projection painting data */
+               ps.projectIsBackfaceCull = 1;
+               ps.projectIsOcclude = 1;
+               ps.projectSeamBleed = 2.0; /* pixel num to bleed  */
+               
+               project_paint_begin(&ps, mval);
+               
+       } else {
+               if (!((s.brush->flag & (BRUSH_ALPHA_PRESSURE|BRUSH_SIZE_PRESSURE|
+                       BRUSH_SPACING_PRESSURE|BRUSH_RAD_PRESSURE)) && (get_activedevice() != 0) && (pressure >= 0.99f)))
+                       imapaint_paint_stroke(&s, painter, texpaint, prevmval, mval, time, pressure);
+       }
        /* paint loop */
        do {
                getmouseco_areawin(mval);
@@ -860,16 +2596,24 @@ void imagepaint_paint(short mousebutton, short texpaint)
                        
                time= PIL_check_seconds_timer();
 
-               if((mval[0] != prevmval[0]) || (mval[1] != prevmval[1])) {
-                       imapaint_paint_stroke(&s, painter, texpaint, prevmval, mval, time, pressure);
-                       prevmval[0]= mval[0];
-                       prevmval[1]= mval[1];
+               if (project) { /* Projection Painting */
+                       if((mval[0] != prevmval[0]) || (mval[1] != prevmval[1])) {
+                               imapaint_paint_stroke_project(&ps, painter, prevmval, mval, time, pressure);
+                               prevmval[0]= mval[0];
+                               prevmval[1]= mval[1];
+                       } else
+                               BIF_wait_for_statechange();
+               } else {
+                       if((mval[0] != prevmval[0]) || (mval[1] != prevmval[1])) {
+                               imapaint_paint_stroke(&s, painter, texpaint, prevmval, mval, time, pressure);
+                               prevmval[0]= mval[0];
+                               prevmval[1]= mval[1];
+                       }
+                       else if (s.brush->flag & BRUSH_AIRBRUSH)
+                               imapaint_paint_stroke(&s, painter, texpaint, prevmval, mval, time, pressure);
+                       else
+                               BIF_wait_for_statechange();
                }
-               else if (s.brush->flag & BRUSH_AIRBRUSH)
-                       imapaint_paint_stroke(&s, painter, texpaint, prevmval, mval, time, pressure);
-               else
-                       BIF_wait_for_statechange();
-
                /* do mouse checking at the end, so don't check twice, and potentially
                   miss a short tap */
        } while(get_mbut() & mousebutton);
@@ -879,6 +2623,10 @@ void imagepaint_paint(short mousebutton, short texpaint)
        imapaint_canvas_free(&s);
        brush_painter_free(painter);
 
+       if (project) {
+               project_paint_end(&ps);
+       }
+       
        imapaint_redraw(1, texpaint, s.image);
        undo_imagepaint_push_end();