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