[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17334] branches/projection-paint/source/ blender/src/imagepaint.c: 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.
Campbell Barton
ideasman42 at gmail.com
Wed Nov 5 15:45:54 CET 2008
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. @@
More information about the Bf-blender-cvs
mailing list