Added option to use another UV layer as a clone source, to paint from one uv layer's image and UVs into the active layer.
This commit is contained in:
parent
a54dc97c13
commit
52ab2f5200
@ -348,6 +348,7 @@ typedef struct ImagePaintSettings {
|
||||
|
||||
/* for projection painting only - todo - use flags */
|
||||
float seam_bleed;
|
||||
int clone_layer, pad;
|
||||
} ImagePaintSettings;
|
||||
|
||||
typedef struct ParticleBrushData {
|
||||
@ -805,6 +806,7 @@ typedef struct Scene {
|
||||
#define IMAGEPAINT_PROJECT_XRAY 8
|
||||
#define IMAGEPAINT_PROJECT_BACKFACE 16
|
||||
#define IMAGEPAINT_PROJECT_IGNORE_SEAMS 32
|
||||
#define IMAGEPAINT_PROJECT_CLONE_LAYER 64
|
||||
|
||||
/* toolsettings->uvcalc_flag */
|
||||
#define UVCALC_FILLHOLES 1
|
||||
|
@ -6392,11 +6392,42 @@ static void editing_panel_mesh_paint(void)
|
||||
|
||||
yco -= 110;
|
||||
|
||||
uiBlockSetCol(block, TH_BUT_SETTING2);
|
||||
id= (mtex)? (ID*)mtex->tex: NULL;
|
||||
xco= std_libbuttons(block, 0, yco, 0, NULL, B_BTEXBROWSE, ID_TE, 0, id, NULL, &(G.buts->menunr), 0, 0, B_BTEXDELETE, 0, 0);
|
||||
/*uiDefButBitS(block, TOG|BIT, BRUSH_FIXED_TEX, B_BRUSHCHANGE, "Fixed", xco+5,yco,butw,19, &brush->flag, 0, 0, 0, 0, "Keep texture origin in fixed position");*/
|
||||
uiBlockSetCol(block, TH_AUTO);
|
||||
if (settings->imapaint.tool == PAINT_TOOL_CLONE) {
|
||||
Object *ob = OBACT;
|
||||
if (ob) {
|
||||
Mesh *me = ob->data;
|
||||
int layercount = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
|
||||
if (layercount>1 && layercount < 12) { /* could allow any number but limit of 11 means no malloc needed */
|
||||
|
||||
butw = 80;
|
||||
uiBlockBeginAlign(block);
|
||||
uiDefButBitS(block, TOG|BIT, IMAGEPAINT_PROJECT_CLONE_LAYER, B_REDR, "Clone Layer", 0,yco,butw,20, &settings->imapaint.flag, 0, 0, 0, 0, "Use another UV layer as clone source, otherwise use 3D the cursor as the source");
|
||||
|
||||
if (settings->imapaint.flag & IMAGEPAINT_PROJECT_CLONE_LAYER) {
|
||||
char str_menu[384], *str_pt; /*384 allows for 11 layers */
|
||||
|
||||
if (settings->imapaint.clone_layer >= layercount) {
|
||||
settings->imapaint.clone_layer = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*str_pt = (char *)MEM_mallocN(layercount*40 , "uvmenu"); str[0]='\0';*/
|
||||
str_pt = str_menu;
|
||||
str_pt[0]='\0';
|
||||
mesh_layers_menu_concat(&me->fdata, CD_MTFACE, str_pt);
|
||||
uiDefButI(block, MENU, B_NOP, str_menu ,butw,yco,(180-butw) + 20,20, &settings->imapaint.clone_layer, 0, 0, 0, 0, "Active UV Layer for editing");
|
||||
}
|
||||
uiBlockEndAlign(block);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uiBlockSetCol(block, TH_BUT_SETTING2);
|
||||
id= (mtex)? (ID*)mtex->tex: NULL;
|
||||
xco= std_libbuttons(block, 0, yco, 0, NULL, B_BTEXBROWSE, ID_TE, 0, id, NULL, &(G.buts->menunr), 0, 0, B_BTEXDELETE, 0, 0);
|
||||
/*uiDefButBitS(block, TOG|BIT, BRUSH_FIXED_TEX, B_BRUSHCHANGE, "Fixed", xco+5,yco,butw,19, &brush->flag, 0, 0, 0, 0, "Keep texture origin in fixed position");*/
|
||||
uiBlockSetCol(block, TH_AUTO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -209,6 +209,7 @@ typedef struct ProjectPaintState {
|
||||
MVert *dm_mvert;
|
||||
MFace *dm_mface;
|
||||
MTFace *dm_mtface;
|
||||
MTFace *dm_mtface_clone; /* other UV layer, use for cloning between layers */
|
||||
|
||||
/* projection painting only */
|
||||
MemArena *arena; /* use for alocating many pixel structs and link-lists */
|
||||
@ -239,7 +240,7 @@ typedef struct ProjectPaintState {
|
||||
#endif
|
||||
/* clone vars */
|
||||
float clone_offset[2];
|
||||
|
||||
int clone_layer; /* -1 when not in use */
|
||||
|
||||
float projectMat[4][4]; /* Projection matrix, use for getting screen coords */
|
||||
float viewMat[4][4];
|
||||
@ -1208,9 +1209,9 @@ static void 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 pixelScreenCo[4],
|
||||
float w[3])
|
||||
{
|
||||
float w[3];
|
||||
BarycentricWeightsSimple2f(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];
|
||||
@ -1223,9 +1224,10 @@ static void 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 pixelScreenCo[4],
|
||||
float w[3])
|
||||
{
|
||||
float w[3], wtot;
|
||||
float wtot;
|
||||
BarycentricWeightsSimple2f(uv1co,uv2co,uv3co,uv,w);
|
||||
|
||||
/* re-weight from the 4th coord of each screen vert */
|
||||
@ -1251,7 +1253,7 @@ static void screen_px_from_persp(
|
||||
|
||||
/* run this function when we know a bucket's, face's pixel can be initialized,
|
||||
* adding to the LinkList 'ps->bucketRect' */
|
||||
static void project_paint_uvpixel_init(ProjectPaintState *ps, int thread_index, ImBuf *ibuf, short x, short y, int bucket_index, int face_index, int image_index, float pixelScreenCo[4])
|
||||
static void project_paint_uvpixel_init(ProjectPaintState *ps, int thread_index, ImBuf *ibuf, short x, short y, int bucket_index, int face_index, int image_index, float pixelScreenCo[4], int side, float w[3])
|
||||
{
|
||||
ProjectPixel *projPixel;
|
||||
short size;
|
||||
@ -1309,21 +1311,63 @@ static void project_paint_uvpixel_init(ProjectPaintState *ps, int thread_index,
|
||||
|
||||
/* done with view3d_project_float inline */
|
||||
if (ps->tool==PAINT_TOOL_CLONE) {
|
||||
float co[2];
|
||||
|
||||
/* 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->clone_offset);
|
||||
|
||||
/* 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 (ibuf->rect_float) {
|
||||
if (!project_paint_PickColor(ps, co, ((ProjectPixelCloneFloat *)projPixel)->clonepx, NULL, 1)) {
|
||||
((ProjectPixelCloneFloat *)projPixel)->clonepx[3] = 0; /* zero alpha - ignore */
|
||||
if (ps->dm_mtface_clone) {
|
||||
/* TODO - float buffer */
|
||||
ImBuf *ibuf_other;
|
||||
MTFace *tf_other = ps->dm_mtface_clone + face_index;
|
||||
float *uvCo1, *uvCo2, *uvCo3;
|
||||
if (side==1) {
|
||||
uvCo1 = tf_other->uv[0];
|
||||
uvCo2 = tf_other->uv[2];
|
||||
uvCo3 = tf_other->uv[3];
|
||||
} else {
|
||||
uvCo1 = tf_other->uv[0];
|
||||
uvCo2 = tf_other->uv[1];
|
||||
uvCo3 = tf_other->uv[2];
|
||||
}
|
||||
|
||||
((ProjectPixelClone *)projPixel)->clonepx[3] = 0;
|
||||
|
||||
if (tf_other->tpage && ( ibuf_other = BKE_image_get_ibuf((Image *)tf_other->tpage, NULL) )) {
|
||||
/* BKE_image_get_ibuf - TODO - this may be slow */
|
||||
|
||||
float uv_other[2], x, y;
|
||||
|
||||
uv_other[0] = w[0]*uvCo1[0] + w[1]*uvCo2[0] + w[2]*uvCo3[0];
|
||||
uv_other[1] = w[0]*uvCo1[1] + w[1]*uvCo2[1] + w[2]*uvCo3[1];
|
||||
|
||||
/* use */
|
||||
x = (float)fmod(uv_other[0], 1.0);
|
||||
y = (float)fmod(uv_other[1], 1.0);
|
||||
|
||||
if (x < 0.0) x += 1.0;
|
||||
if (y < 0.0) y += 1.0;
|
||||
|
||||
x = x * ibuf_other->x - 0.5;
|
||||
y = y * ibuf_other->y - 0.5;
|
||||
|
||||
bicubic_interpolation_px(ibuf_other, x, y, NULL, ((ProjectPixelClone *)projPixel)->clonepx);
|
||||
} else {
|
||||
((ProjectPixelClone *)projPixel)->clonepx[3] = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!project_paint_PickColor(ps, co, NULL, ((ProjectPixelClone *)projPixel)->clonepx, 1)) {
|
||||
((ProjectPixelClone *)projPixel)->clonepx[3] = 0; /* zero alpha - ignore */
|
||||
float co[2];
|
||||
|
||||
/* 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->clone_offset);
|
||||
|
||||
/* 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 (ibuf->rect_float) {
|
||||
if (!project_paint_PickColor(ps, co, ((ProjectPixelCloneFloat *)projPixel)->clonepx, NULL, 1)) {
|
||||
((ProjectPixelCloneFloat *)projPixel)->clonepx[3] = 0; /* zero alpha - ignore */
|
||||
}
|
||||
} else {
|
||||
if (!project_paint_PickColor(ps, co, NULL, ((ProjectPixelClone *)projPixel)->clonepx, 1)) {
|
||||
((ProjectPixelClone *)projPixel)->clonepx[3] = 0; /* zero alpha - ignore */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1544,6 +1588,8 @@ static void project_paint_face_init(ProjectPaintState *ps, int thread_index, int
|
||||
|
||||
float *vCo[4]; /* vertex screenspace coords */
|
||||
|
||||
float w[3];
|
||||
|
||||
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];
|
||||
int i;
|
||||
@ -1632,12 +1678,12 @@ static void project_paint_face_init(ProjectPaintState *ps, int thread_index, int
|
||||
IsectPT2Df(uv, uv1co, uv2co, uv3co) ) {
|
||||
|
||||
if (ps->is_ortho) {
|
||||
screen_px_from_ortho(ps, uv, v1coSS,v2coSS,v3coSS, uv1co,uv2co,uv3co, pixelScreenCo);
|
||||
screen_px_from_ortho(ps, uv, v1coSS,v2coSS,v3coSS, uv1co,uv2co,uv3co, pixelScreenCo, w);
|
||||
} else {
|
||||
screen_px_from_persp(ps, uv, v1coSS,v2coSS,v3coSS, uv1co,uv2co,uv3co, pixelScreenCo);
|
||||
screen_px_from_persp(ps, uv, v1coSS,v2coSS,v3coSS, uv1co,uv2co,uv3co, pixelScreenCo, w);
|
||||
}
|
||||
|
||||
project_paint_uvpixel_init(ps, thread_index, ibuf, x, y, bucket_index, face_index, image_index, pixelScreenCo);
|
||||
project_paint_uvpixel_init(ps, thread_index, ibuf, x, y, bucket_index, face_index, image_index, pixelScreenCo, i, w);
|
||||
|
||||
has_x_isect = has_isect = 1;
|
||||
} else if (has_x_isect) {
|
||||
@ -1692,6 +1738,7 @@ static void project_paint_face_init(ProjectPaintState *ps, int thread_index, int
|
||||
float bucket_clip_edges[2][2]; /* store the screenspace coords of the face, clipped by the bucket's screen aligned rectangle */
|
||||
float edge_verts_inset_clip[2][3];
|
||||
int fidx1, fidx2; /* face edge pairs - loop throuh these ((0,1), (1,2), (2,3), (3,0)) or ((0,1), (1,2), (2,0)) for a tri */
|
||||
int side;
|
||||
|
||||
float seam_subsection[4][2];
|
||||
float fac1, fac2, ftot;
|
||||
@ -1731,6 +1778,9 @@ static void project_paint_face_init(ProjectPaintState *ps, int thread_index, int
|
||||
|
||||
if (ftot > 0.0) { /* avoid div by zero */
|
||||
|
||||
if (fidx1==2 || fidx2==2) side = 1;
|
||||
else side = 0;
|
||||
|
||||
fac1 = Vec2Lenf(vCoSS[fidx1], bucket_clip_edges[0]) / ftot;
|
||||
fac2 = Vec2Lenf(vCoSS[fidx1], bucket_clip_edges[1]) / ftot;
|
||||
|
||||
@ -1792,7 +1842,18 @@ static void project_paint_face_init(ProjectPaintState *ps, int thread_index, int
|
||||
pixelScreenCo[2] = pixelScreenCo[2]/pixelScreenCo[3]; /* Use the depth for bucket point occlusion */
|
||||
}
|
||||
|
||||
project_paint_uvpixel_init(ps, thread_index, ibuf, x, y, bucket_index, face_index, image_index, pixelScreenCo);
|
||||
if (ps->dm_mtface_clone) {
|
||||
/* TODO, this is not QUITE correct since UV is not inside the UV's but good enough for seams */
|
||||
if (side) {
|
||||
BarycentricWeightsSimple2f(tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], uv, w);
|
||||
} else {
|
||||
BarycentricWeightsSimple2f(tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], uv, w);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
project_paint_uvpixel_init(ps, thread_index, ibuf, x, y, bucket_index, face_index, image_index, pixelScreenCo, side, w); /* TODO - side */
|
||||
} else if (has_x_isect) {
|
||||
/* assuming the face is not a bow-tie - we know we cant intersect again on the X */
|
||||
break;
|
||||
@ -2076,6 +2137,17 @@ static void project_paint_begin( ProjectPaintState *ps, short mval[2])
|
||||
ps->dm_totvert = ps->dm->getNumVerts( ps->dm );
|
||||
ps->dm_totface = ps->dm->getNumFaces( ps->dm );
|
||||
|
||||
/* use clone mtface? */
|
||||
|
||||
if ( ps->tool != PAINT_TOOL_CLONE ||
|
||||
ps->clone_layer==-1 ||
|
||||
ps->clone_layer >= CustomData_number_of_layers(&ps->dm->faceData, CD_MTFACE)
|
||||
) {
|
||||
ps->dm_mtface_clone = NULL;
|
||||
} else {
|
||||
ps->dm_mtface_clone = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, ps->clone_layer);
|
||||
}
|
||||
|
||||
ps->viewDir[0] = 0.0;
|
||||
ps->viewDir[1] = 0.0;
|
||||
ps->viewDir[2] = 1.0;
|
||||
@ -3695,6 +3767,12 @@ void imagepaint_paint(short mousebutton, short texpaint)
|
||||
/* setup projection painting data */
|
||||
ps.do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1;
|
||||
ps.do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1;
|
||||
if (settings->imapaint.flag & IMAGEPAINT_PROJECT_CLONE_LAYER) {
|
||||
ps.clone_layer = settings->imapaint.clone_layer;
|
||||
} else {
|
||||
ps.clone_layer = -1;
|
||||
}
|
||||
|
||||
#ifndef PROJ_DEBUG_NOSEAMBLEED
|
||||
if (settings->imapaint.flag & IMAGEPAINT_PROJECT_IGNORE_SEAMS) {
|
||||
ps.seam_bleed_px = 0.0;
|
||||
|
Loading…
Reference in New Issue
Block a user