Revision: 17334
          
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17334
Author:   campbellbarton
Date:     2008-11-05 15:45:54 +0100 (Wed, 05 Nov 2008)

Log Message:
-----------
projection painting clone tool - gives a similar work flow to cloning in the 
gimp, Ctrl+Click to set the cursor source, then paint from this location.

todo...
* pixel interpolation.
* clone option can currently only be set from the image paint panel.
* only initialize clone pixels under the mouse.
* overlap between source/target while painting could cause problems. need to 
look into this.

also fixed some cashes in painting normally.

Modified Paths:
--------------
    branches/projection-paint/source/blender/src/imagepaint.c

Modified: branches/projection-paint/source/blender/src/imagepaint.c
===================================================================
--- branches/projection-paint/source/blender/src/imagepaint.c   2008-11-05 
13:22:10 UTC (rev 17333)
+++ branches/projection-paint/source/blender/src/imagepaint.c   2008-11-05 
14:45:54 UTC (rev 17334)
@@ -145,8 +145,9 @@
 #define PROJ_FACE_SEAM4        1<<5
 
 
-#define PROJ_BUCKET_NULL       0
-#define PROJ_BUCKET_INIT       1
+#define PROJ_BUCKET_NULL               0
+#define PROJ_BUCKET_INIT               1<<0
+// #define PROJ_BUCKET_CLONE_INIT      1<<1
 
 /* only for readability */
 #define PROJ_BUCKET_LEFT               0
@@ -217,8 +218,10 @@
 } ProjectPixel;
 
 typedef struct ProjectPixelClone {
-       struct ProjectPixel;
-       void *source;
+       struct ProjectPixel __pp;
+       char backbuf[4];        /* TODO - float buffer? */
+       char clonebuf[4];
+       //void *source;         /* pointer to source pixels */
 } ProjectPixelClone;
 
 /* Finish projection painting structs */
@@ -396,15 +399,144 @@
                (       (       (int)(( (projCo2D[1] - ps->viewMin2D[1])  / 
ps->viewHeight) * ps->bucketsY)) * ps->bucketsX );
 }
 
+static int project_paint_BucketOffsetSafe(ProjectPaintState *ps, float 
*projCo2D)
+{
+       int bucket_index = project_paint_BucketOffset(ps, projCo2D);
+       
+       if (bucket_index < 0 || bucket_index >= ps->bucketsX*ps->bucketsY) {    
+               return -1;
+       } else {
+               return bucket_index;
+       }
+}
+
+/* assume they intersect */
+static void BarryCentricWeights2f(float v1[2], float v2[2], float v3[2], float 
pt[2], float w[3]) {
+       float wtot;
+       w[0] = AreaF2Dfl(v2, v3, pt);
+       w[1] = AreaF2Dfl(v3, v1, pt);
+       w[2] = AreaF2Dfl(v1, v2, pt);
+       wtot = w[0]+w[1]+w[2];
+       w[0]/=wtot;
+       w[1]/=wtot;
+       w[2]/=wtot;
+}
+
+static float tri_depth_2d(float v1[3], float v2[3], float v3[3], float pt[2], 
float w[3])
+{
+       BarryCentricWeights2f(v1,v2,v3,pt,w);
+       return (v1[2]*w[0]) + (v2[2]*w[1]) + (v3[2]*w[2]);
+}
+
+
+/* return the topmost face  in screen coords index or -1
+ * bucket_index can be -1 if we dont know it to begin with */
+static int screenco_pickface(ProjectPaintState *ps, float pt[2], float w[3], 
int *side) {
+       LinkNode *node;
+       float w_tmp[3];
+       float *v1, *v2, *v3, *v4;
+       int bucket_index;
+       int face_index;
+       int best_side = -1;
+       int best_face_index = -1;
+       float z_depth_best = MAXFLOAT, z_depth;
+       MFace *mf;
+       
+       bucket_index = project_paint_BucketOffsetSafe(ps, pt);
+       if (bucket_index==-1)
+               return -1;
+       
+       node = ps->projectFaces[bucket_index];
+       
+       /* we could return 0 for 1 face buckets, as long as this function 
assumes
+        * that the point its testing is only every originated from an existing 
face */
+       
+       while (node) {
+               face_index = (int)node->link;
+               mf = ps->dm_mface + face_index;
+               
+               v1 = ps->projectVertScreenCos[mf->v1];
+               v2 = ps->projectVertScreenCos[mf->v2];
+               v3 = ps->projectVertScreenCos[mf->v3];
+               
+               if ( IsectPT2Df(pt, v1, v2, v3) ) {
+                       z_depth = tri_depth_2d(v1,v2,v3,pt,w_tmp);
+                       if (z_depth < z_depth_best) {
+                               best_face_index = face_index;
+                               best_side = 0;
+                               z_depth_best = z_depth;
+                               VECCOPY(w, w_tmp);
+                       }
+               } else if (mf->v4) {
+                       v4 = ps->projectVertScreenCos[mf->v4];
+                       
+                       if ( IsectPT2Df(pt, v1, v3, v4) ) {
+                               z_depth = tri_depth_2d(v1,v3,v4,pt,w_tmp);
+                               if (z_depth < z_depth_best) {
+                                       best_face_index = face_index;
+                                       best_side = 1;
+                                       z_depth_best = z_depth;
+                                       VECCOPY(w, w_tmp);
+                               }
+                       }
+               }
+               
+               node = node->next;
+       }
+       
+       *side = best_side;
+       return best_face_index; /* will be -1 or a valid face */
+}
+
+/* bucket_index is optional, since in some cases we know it */
+static int screenco_pickcol(ProjectPaintState *ps, int bucket_index, float 
pt[2], char rgba[4])
+{
+       float w[3], uv[2];
+       int side;
+       int face_index;
+       MTFace *tf;
+       ImBuf *ibuf;
+       int x,y;
+       char *pixel;
+       
+       face_index = screenco_pickface(ps,pt,w, &side);
+       
+       if (face_index == -1)
+               return 0;
+       
+       tf = ps->dm_mtface + face_index;
+       
+       if (side==0) {
+               uv[0] = tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + 
tf->uv[2][0]*w[2];
+               uv[1] = tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + 
tf->uv[2][1]*w[2];
+       } else { /* QUAD */
+               uv[0] = tf->uv[0][0]*w[0] + tf->uv[2][0]*w[1] + 
tf->uv[3][0]*w[2];
+               uv[1] = tf->uv[0][1]*w[0] + tf->uv[2][1]*w[1] + 
tf->uv[3][1]*w[2];
+       }
+       
+       ibuf = BKE_image_get_ibuf((Image *)tf->tpage, NULL); /* TODO - this may 
be slow */
+       
+       x = uv[0]*ibuf->x;
+       y = uv[1]*ibuf->y;
+       
+       if (x<0 || x>=ibuf->x  ||  y<0 || y>=ibuf->y) return 0;
+       
+       pixel = (( char * ) ibuf->rect) + (( x + y * ibuf->x ) * 4);
+       
+       rgba[0] = pixel[0];
+       rgba[1] = pixel[1];
+       rgba[2] = pixel[2];
+       rgba[3] = pixel[3];
+       return 1;
+}
+
 /* return...
  * 0   : no occlusion
  * -1  : no occlusion but 2D intersection is true (avoid testing the other 
half of a quad)
  * 1   : occluded */
 
-static int screenco_tri_pt_occlude(float *pt, float *v1, float *v2, float *v3)
+static int screenco_tri_pt_occlude(float pt[3], float v1[3], float v2[3], 
float v3[3])
 {
-       float w1, w2, w3, wtot; /* weights for converting the pixel into 3d 
worldspace coords */
-       
        /* if all are behind us, return false */
        if(v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2])
                return 0;
@@ -419,13 +551,9 @@
        if(     v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) {
                return 1;
        } else {
+               float w[3];
                /* we intersect? - find the exact depth at the point of 
intersection */
-               w1 = AreaF2Dfl(v2, v3, pt);
-               w2 = AreaF2Dfl(v3, v1, pt);
-               w3 = AreaF2Dfl(v1, v2, pt);
-               wtot = w1 + w2 + w3;
-               
-               if ((v1[2]*w1/wtot) + (v2[2]*w2/wtot) + (v3[2]*w3/wtot) < 
pt[2]) {
+               if (tri_depth_2d(v1,v2,v3,pt,w) < pt[2]) {
                        return 1; /* This point is occluded by another face */
                }
        }
@@ -497,7 +625,7 @@
 #define ISECT_TRUE 1
 #define ISECT_TRUE_P1 2
 #define ISECT_TRUE_P2 3
-static int project_scanline_isect(float *p1, float *p2, float y_level, float 
*x_isect)
+static int project_scanline_isect(float p1[2], float p2[2], float y_level, 
float *x_isect)
 {
        if (y_level==p1[1]) {
                *x_isect = p1[0];
@@ -519,7 +647,7 @@
        }
 }
 
-static int project_face_scanline(ProjectScanline *sc, float y_level, float 
*v1, float *v2, float *v3, float *v4)
+static int project_face_scanline(ProjectScanline *sc, float y_level, float 
v1[2], float v2[2], float v3[2], float v4[2])
 {      
        /* Create a scanlines for the face at this Y level 
         * triangles will only ever have 1 scanline, quads may have 2 */
@@ -614,7 +742,7 @@
        return totscanlines;
 }
 
-static int cmp_uv(float *vec2a, float *vec2b)
+static int cmp_uv(float vec2a[2], float vec2b[2])
 {
        return ((fabs(vec2a[0]-vec2b[0]) < 0.0001) && (fabs(vec2a[1]-vec2b[1]) 
< 0.0001)) ? 1:0;
 }
@@ -712,7 +840,7 @@
 }
 
 /* return zero if there is no area in the returned rectangle */
-static int uv_image_rect(float *uv1, float *uv2, float *uv3, float *uv4, int 
*min_px, int *max_px, int x_px, int y_px, int is_quad)
+static int uv_image_rect(float uv1[2], float uv2[2], float uv3[2], float 
uv4[2], int min_px[2], int max_px[2], int x_px, int y_px, int is_quad)
 {
        float min_uv[2], max_uv[2]; /* UV bounds */
        int i;
@@ -862,41 +990,29 @@
 }
 
 static screen_px_from_ortho(
-               ProjectPaintState *ps, float *uv,
-               float *v1co, float *v2co, float *v3co, /* Screenspace coords */
-               float *uv1co, float *uv2co, float *uv3co,
-               float *pixelScreenCo )
+               ProjectPaintState *ps, float uv[2],
+               float v1co[3], float v2co[3], float v3co[3], /* Screenspace 
coords */
+               float uv1co[2], float uv2co[2], float uv3co[2],
+               float pixelScreenCo[4] )
 {
-       float w1, w2, w3, wtot; /* weights for converting the pixel into 3d 
screenspace coords */
-       w1 = AreaF2Dfl(uv2co, uv3co, uv);
-       w2 = AreaF2Dfl(uv3co, uv1co, uv);
-       w3 = AreaF2Dfl(uv1co, uv2co, uv);
-       
-       wtot = w1 + w2 + w3;
-       w1 /= wtot; w2 /= wtot; w3 /= wtot;
-       
-       pixelScreenCo[0] = v1co[0]*w1 + v2co[0]*w2 + v3co[0]*w3;
-       pixelScreenCo[1] = v1co[1]*w1 + v2co[1]*w2 + v3co[1]*w3;
-       pixelScreenCo[2] = v1co[2]*w1 + v2co[2]*w2 + v3co[2]*w3;        
+       float w[3];
+       BarryCentricWeights2f(uv1co,uv2co,uv3co,uv,w);
+       pixelScreenCo[0] = v1co[0]*w[0] + v2co[0]*w[1] + v3co[0]*w[2];
+       pixelScreenCo[1] = v1co[1]*w[0] + v2co[1]*w[1] + v3co[1]*w[2];
+       pixelScreenCo[2] = v1co[2]*w[0] + v2co[2]*w[1] + v3co[2]*w[2];  
 }
 
 static screen_px_from_persp(
-               ProjectPaintState *ps, float *uv,
-               float *v1co, float *v2co, float *v3co, /* Worldspace coords */
-               float *uv1co, float *uv2co, float *uv3co,
-               float *pixelScreenCo )
+               ProjectPaintState *ps, float uv[2],
+               float v1co[3], float v2co[3], float v3co[3], /* Worldspace 
coords */
+               float uv1co[2], float uv2co[2], float uv3co[2],
+               float pixelScreenCo[4])
 {
-       float w1, w2, w3, wtot; /* weights for converting the pixel into 3d 
screenspace coords */
-       w1 = AreaF2Dfl(uv2co, uv3co, uv);
-       w2 = AreaF2Dfl(uv3co, uv1co, uv);
-       w3 = AreaF2Dfl(uv1co, uv2co, uv);
-       
-       wtot = w1 + w2 + w3;
-       w1 /= wtot; w2 /= wtot; w3 /= wtot;
-       
-       pixelScreenCo[0] = v1co[0]*w1 + v2co[0]*w2 + v3co[0]*w3;
-       pixelScreenCo[1] = v1co[1]*w1 + v2co[1]*w2 + v3co[1]*w3;
-       pixelScreenCo[2] = v1co[2]*w1 + v2co[2]*w2 + v3co[2]*w3;        
+       float w[3];
+       BarryCentricWeights2f(uv1co,uv2co,uv3co,uv,w);
+       pixelScreenCo[0] = v1co[0]*w[0] + v2co[0]*w[1] + v3co[0]*w[2];
+       pixelScreenCo[1] = v1co[1]*w[0] + v2co[1]*w[1] + v3co[1]*w[2];
+       pixelScreenCo[2] = v1co[2]*w[0] + v2co[2]*w[1] + v3co[2]*w[2];
        pixelScreenCo[3] = 1.0;
        
        Mat4MulVec4fl(ps->projectMat, pixelScreenCo);
@@ -908,10 +1024,13 @@
        pixelScreenCo[2] = pixelScreenCo[2]/pixelScreenCo[3]; /* Use the depth 
for bucket point occlusion */
 }
 
-/* can provide own own coords, use for seams when we want to bleed our from 
the original location */
 
+static void project_paint_bucket_init(ProjectPaintState *ps, int bucket_index);
+
+/* Only run this function once for new ProjectPixelClone's */
 #define pixel_size 4
-static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, 
float *uv,  int x, int y, int face_index, float *pixelScreenCo)
+
+static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, 
float uv[2], int x, int y, int face_index, float pixelScreenCo[4])
 {
        int bucket_index;
        
@@ -919,10 +1038,10 @@
        
        ProjectPixel *projPixel;
        
-       bucket_index = project_paint_BucketOffset(ps, pixelScreenCo);
+       bucket_index = project_paint_BucketOffsetSafe(ps, pixelScreenCo);
        
        /* even though it should be clamped, in some cases it can still run 
over */
-       if (bucket_index < 0 || bucket_index >= ps->bucketsX * ps->bucketsY)
+       if (bucket_index==-1)
                return;
        
        /* Use viewMin2D to make (0,0) the bottom left of the bounds 
@@ -931,13 +1050,39 @@
        /* Is this UV visible from the view? - raytrace */

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to