Bugfix: texture paint didn't work correct with modifiers.

This commit is contained in:
Brecht Van Lommel
2006-09-12 16:53:27 +00:00
parent e02e8b0c71
commit 737458d2f4
3 changed files with 101 additions and 49 deletions

View File

@@ -472,6 +472,11 @@ struct BrushPainter {
short firsttouch; /* first paint op */
float startsize;
float startalpha;
float startinnerradius;
float startspacing;
BrushPainterCache cache;
};
@@ -483,6 +488,11 @@ BrushPainter *brush_painter_new(Brush *brush)
painter->firsttouch= 1;
painter->cache.lastsize= -1; /* force ibuf create in refresh */
painter->startsize = brush->size;
painter->startalpha = brush->alpha;
painter->startinnerradius = brush->innerradius;
painter->startspacing = brush->spacing;
return painter;
}
@@ -510,6 +520,13 @@ void brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly
void brush_painter_free(BrushPainter *painter)
{
Brush *brush = painter->brush;
brush->size = painter->startsize;
brush->alpha = painter->startalpha;
brush->innerradius = painter->startinnerradius;
brush->spacing = painter->startspacing;
if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf);
@@ -757,9 +774,10 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
#endif
else {
float startdistance, spacing, step, paintpos[2], dmousepos[2];
float brushsize = MAX2(1.0, brush->size);
/* compute brush spacing adapted to brush size */
spacing= brush->size*brush->spacing*0.01f;
spacing= brushsize*brush->spacing*0.01f;
/* setup starting distance, direction vector and accumulated distance */
startdistance= painter->accumdistance;

View File

@@ -56,7 +56,9 @@
#include "DNA_view3d_types.h"
#include "BKE_brush.h"
#include "BKE_customdata.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
@@ -1535,9 +1537,8 @@ static void texpaint_project(Object *ob, double *model, double *proj, GLint *vie
pco[1]= (float)winy;
}
static int texpaint_projected_verts(Object *ob, Mesh *mesh, TFace *tf, float *v1, float *v2, float *v3, float *v4)
static int texpaint_projected_verts(Object *ob, MFace *mf, TFace *tf, MVert *mv, float *v1, float *v2, float *v3, float *v4)
{
MFace *mf = mesh->mface + (tf - mesh->tface);
double model[16], proj[16];
GLint view[4];
@@ -1550,53 +1551,85 @@ static int texpaint_projected_verts(Object *ob, Mesh *mesh, TFace *tf, float *v1
view[0] = view[1] = 0;
/* project the verts */
texpaint_project(ob, model, proj, view, (mesh->mvert+mf->v1)->co, v1);
texpaint_project(ob, model, proj, view, (mesh->mvert+mf->v2)->co, v2);
texpaint_project(ob, model, proj, view, (mesh->mvert+mf->v3)->co, v3);
texpaint_project(ob, model, proj, view, mv[0].co, v1);
texpaint_project(ob, model, proj, view, mv[1].co, v2);
texpaint_project(ob, model, proj, view, mv[2].co, v3);
if(mf->v4)
texpaint_project(ob, model, proj, view, (mesh->mvert+mf->v4)->co, v4);
texpaint_project(ob, model, proj, view, mv[3].co, v4);
return (mf->v4? 4: 3);
}
/* compute uv coordinates of mouse in face */
void texpaint_pick_uv(Object *ob, Mesh *mesh, TFace *tf, short *xy, float *uv)
void texpaint_pick_uv(Object *ob, Mesh *mesh, unsigned int faceindex, short *xy, float *uv)
{
float v1[2], v2[2], v3[2], v4[2], p[2], w[3], w2[3];
float absw, absw2;
int nvert;
float v1[2], v2[2], v3[2], v4[2], p[2], w[3];
float absw, minabsw;
int nvert, dmNeedsFree;
DerivedMesh *dm = mesh_get_derived_final(ob, &dmNeedsFree);
int *index = dm->getFaceDataArray(dm, LAYERTYPE_ORIGINDEX);
TFace *tface = dm->getFaceDataArray(dm, LAYERTYPE_TFACE), *tf;
int numfaces = dm->getNumFaces(dm), a;
MFace mf;
MVert mv[4];
/* compute barycentric coordinates of point in face and interpolate uv's.
it's ok to compute the barycentric coords on the projected positions,
because they are invariant under affine transform */
nvert= texpaint_projected_verts(ob, mesh, tf, v1, v2, v3, v4);
minabsw = 1e10;
uv[0] = uv[1] = 0.0;
p[0]= xy[0];
p[1]= xy[1];
/* test all faces in the derivedmesh with the original index of the picked face */
for (a = 0; a < numfaces; a++) {
if (index[a] == faceindex) {
dm->getFace(dm, a, &mf);
if (nvert == 4) {
texpaint_barycentric_2d(v1, v2, v4, p, w);
texpaint_barycentric_2d(v2, v3, v4, p, w2);
dm->getVert(dm, mf.v1, &mv[0]);
dm->getVert(dm, mf.v2, &mv[1]);
dm->getVert(dm, mf.v3, &mv[2]);
if (mf.v4)
dm->getVert(dm, mf.v4, &mv[3]);
/* the triangle with the largest absolute values is the one with the
most negative weights */
absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
absw2= fabs(w2[0]) + fabs(w2[1]) + fabs(w2[2]);
if(absw > absw2) {
uv[0]= tf->uv[1][0]*w2[0] + tf->uv[2][0]*w2[1] + tf->uv[3][0]*w2[2];
uv[1]= tf->uv[1][1]*w2[0] + tf->uv[2][1]*w2[1] + tf->uv[3][1]*w2[2];
}
else {
uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[3][0]*w[2];
uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[3][1]*w[2];
tf= &tface[a];
/* compute barycentric coordinates of point in face and interpolate uv's.
it's ok to compute the barycentric coords on the projected positions,
because they are invariant under affine transform */
nvert= texpaint_projected_verts(ob, &mf, tf, mv, v1, v2, v3, v4);
p[0]= xy[0];
p[1]= xy[1];
if (nvert == 4) {
/* the triangle with the largest absolute values is the one with the
most negative weights */
texpaint_barycentric_2d(v1, v2, v4, p, w);
absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
if(absw < minabsw) {
uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[3][0]*w[2];
uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[3][1]*w[2];
minabsw = absw;
}
texpaint_barycentric_2d(v2, v3, v4, p, w);
absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
if (absw < minabsw) {
uv[0]= tf->uv[1][0]*w[0] + tf->uv[2][0]*w[1] + tf->uv[3][0]*w[2];
uv[1]= tf->uv[1][1]*w[0] + tf->uv[2][1]*w[1] + tf->uv[3][1]*w[2];
minabsw = absw;
}
}
else {
texpaint_barycentric_2d(v1, v2, v3, p, w);
absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
if (absw < minabsw) {
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];
minabsw = absw;
}
}
}
}
else {
texpaint_barycentric_2d(v1, v2, v3, p, w);
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];
}
if (dmNeedsFree)
dm->release(dm);
}
/* Selects all faces which have the same uv-texture as the active face

View File

@@ -112,7 +112,7 @@ typedef struct ImagePaintState {
/* texture paint only */
Object *ob;
Mesh *me;
TFace *tface;
int faceindex;
float uv[2];
} ImagePaintState;
@@ -459,7 +459,7 @@ static void imapaint_compute_uvco(short *mval, float *uv)
/* 3D TexturePaint */
int facesel_face_pick(Mesh *me, short *mval, unsigned int *index, short rect);
void texpaint_pick_uv(Object *ob, Mesh *mesh, TFace *tf, short *xy, float *mousepos);
void texpaint_pick_uv(Object *ob, Mesh *mesh, unsigned int faceindex, short *xy, float *mousepos);
static int texpaint_break_stroke(float *prevuv, float *fwuv, float *bkuv, float *uv)
{
@@ -536,19 +536,17 @@ static int imapaint_do_paint(ImagePaintState *s, BrushPainter *painter, Image *i
static void imapaint_do(ImagePaintState *s, BrushPainter *painter, short texpaint, short *prevmval, short *mval, double time)
{
TFace *newtface = NULL;
Image *newimage = NULL;
float fwuv[2], bkuv[2], newuv[2];
unsigned int face_index;
unsigned int newfaceindex;
int breakstroke = 0, redraw = 0;
if (texpaint) {
/* pick face and image */
if (facesel_face_pick(s->me, mval, &face_index, 0)) {
newtface = s->me->tface + face_index;
newimage = (Image*)newtface->tpage;
texpaint_pick_uv(s->ob, s->me, newtface, mval, newuv);
if (facesel_face_pick(s->me, mval, &newfaceindex, 0)) {
newimage = (Image*)((s->me->tface+newfaceindex)->tpage);
texpaint_pick_uv(s->ob, s->me, newfaceindex, mval, newuv);
}
else
newuv[0] = newuv[1] = 0.0f;
@@ -556,8 +554,8 @@ static void imapaint_do(ImagePaintState *s, BrushPainter *painter, short texpain
/* see if stroke is broken, and if so finish painting in old position */
if (s->image) {
if (newimage == s->image) {
texpaint_pick_uv(s->ob, s->me, s->tface, mval, fwuv);
texpaint_pick_uv(s->ob, s->me, newtface, prevmval, bkuv);
texpaint_pick_uv(s->ob, s->me, s->faceindex, mval, fwuv);
texpaint_pick_uv(s->ob, s->me, newfaceindex, prevmval, bkuv);
breakstroke= texpaint_break_stroke(s->uv, fwuv, bkuv, newuv);
}
else
@@ -565,7 +563,7 @@ static void imapaint_do(ImagePaintState *s, BrushPainter *painter, short texpain
}
if (breakstroke) {
texpaint_pick_uv(s->ob, s->me, s->tface, mval, fwuv);
texpaint_pick_uv(s->ob, s->me, s->faceindex, mval, fwuv);
redraw |= imapaint_do_paint(s, painter, s->image, texpaint, fwuv, time, 1);
imapaint_clear_partial_redraw();
brush_painter_break_stroke(painter);
@@ -585,7 +583,7 @@ static void imapaint_do(ImagePaintState *s, BrushPainter *painter, short texpain
/* update state */
s->image = newimage;
s->tface = newtface;
s->faceindex = newfaceindex;
s->uv[0] = newuv[0];
s->uv[1] = newuv[1];
}
@@ -649,6 +647,8 @@ void imagepaint_paint(short mousebutton, short texpaint)
imapaint_do(&s, painter, texpaint, prevmval, mval, time);
//get_tablet_data();
/* paint loop */
while(get_mbut() & mousebutton) {
getmouseco_areawin(mval);
@@ -658,6 +658,7 @@ void imagepaint_paint(short mousebutton, short texpaint)
imapaint_do(&s, painter, texpaint, prevmval, mval, time);
prevmval[0]= mval[0];
prevmval[1]= mval[1];
//s.brush->size = MAX2(1, MIN2(200, s.brush->size*0.9));
}
else if (s.brush->flag & BRUSH_AIRBRUSH)
imapaint_do(&s, painter, texpaint, prevmval, mval, time);