Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2008-11-09 05:47:30 +0300
committerCampbell Barton <ideasman42@gmail.com>2008-11-09 05:47:30 +0300
commit74d1a04f30f61bbc6623d2f956c6dcaf92bb11dc (patch)
treeb02c25a0a2ba2302e733f62fe2c90e2bec568e58
parentf7135d981a9e08622dfcd1f76fb1bc8f3688c1df (diff)
changes to projection painting
* initializing a bucket only initializes pixels from that bucket (was initializing all pixels in intersecting faces before which made large faces slow to paint onto) * removed scanline functions, they are not as useful when initializing small areas. * UV seam checking also sets the seam flag on the adjacent face to avoid double lookups. TODO - uv seam bleed doesn't work in perspective mode.
-rw-r--r--source/blender/src/imagepaint.c851
1 files changed, 508 insertions, 343 deletions
diff --git a/source/blender/src/imagepaint.c b/source/blender/src/imagepaint.c
index 7dcf1363aaa..e5ce0e9ac6a 100644
--- a/source/blender/src/imagepaint.c
+++ b/source/blender/src/imagepaint.c
@@ -133,17 +133,22 @@ typedef struct ImagePaintState {
/* testing options */
#define PROJ_BUCKET_DIV 128 /* TODO - test other values, this is a guess, seems ok */
-// #define PROJ_DEBUG_PAINT 1
-// #define PROJ_DEBUG_NOSCANLINE 1
+//#define PROJ_DEBUG_PAINT 1
+#define PROJ_DEBUG_NOSCANLINE 1
//#define PROJ_DEBUG_NOSEAMBLEED 1
-/* projectFaceFlags options */
-#define PROJ_FACE_IGNORE 1<<0 /* When the face is hidden, backfacing or occluded */
-#define PROJ_FACE_INIT 1<<1 /* When we have initialized the faces data */
-#define PROJ_FACE_SEAM1 1<<2 /* If this face has a seam on any of its edges */
-#define PROJ_FACE_SEAM2 1<<3
-#define PROJ_FACE_SEAM3 1<<4
-#define PROJ_FACE_SEAM4 1<<5
+/* projectFaceSeamFlags options */
+//#define PROJ_FACE_IGNORE 1<<0 /* When the face is hidden, backfacing or occluded */
+//#define PROJ_FACE_INIT 1<<1 /* When we have initialized the faces data */
+#define PROJ_FACE_SEAM1 1<<0 /* If this face has a seam on any of its edges */
+#define PROJ_FACE_SEAM2 1<<1
+#define PROJ_FACE_SEAM3 1<<2
+#define PROJ_FACE_SEAM4 1<<3
+
+#define PROJ_FACE_NOSEAM1 1<<4
+#define PROJ_FACE_NOSEAM2 1<<5
+#define PROJ_FACE_NOSEAM3 1<<6
+#define PROJ_FACE_NOSEAM4 1<<7
#define PROJ_BUCKET_NULL 0
#define PROJ_BUCKET_INIT 1<<0
@@ -170,25 +175,26 @@ typedef struct ProjectPaintState {
MTFace *dm_mtface;
/* projection painting only */
- MemArena *projectArena; /* use for alocating many pixel structs and link-lists */
- LinkNode **projectBuckets; /* screen sized 2D array, each pixel has a linked list of ProjectPixel's */
- LinkNode **projectFaces; /* projectBuckets alligned array linkList of faces overlapping each bucket */
- char *projectBucketFlags; /* store if the bucks have been initialized */
- char *projectFaceFlags; /* store info about faces, if they are initialized etc*/
- LinkNode **projectVertFaces;/* Only needed for when projectIsSeamBleed is enabled, use to find UV seams */
-
- int bucketsX; /* The size of the bucket grid, the grid span's viewMin2D/viewMax2D so you can paint outsize the screen or with 2 brushes at once */
+ MemArena *projectArena; /* use for alocating many pixel structs and link-lists */
+ LinkNode **projectBuckets; /* screen sized 2D array, each pixel has a linked list of ProjectPixel's */
+ LinkNode **projectFaces; /* projectBuckets alligned array linkList of faces overlapping each bucket */
+ char *projectBucketFlags; /* store if the bucks have been initialized */
+ char *projectFaceSeamFlags; /* store info about faces, if they are initialized etc*/
+ float (*projectFaceSeamUVs)[4][2]; /* expanded UVs for faces to use as seams */
+ LinkNode **projectVertFaces; /* Only needed for when projectSeamBleed is enabled, use to find UV seams */
+
+ int bucketsX; /* The size of the bucket grid, the grid span's viewMin2D/viewMax2D so you can paint outsize the screen or with 2 brushes at once */
int bucketsY;
- Image **projectImages; /* array of images we are painting onto while, use so we can tag for updates */
+ Image **projectImages; /* array of images we are painting onto while, use so we can tag for updates */
- int projectImageTotal; /* size of projectImages array */
- int imaContextIndex; /* current image, use for context switching */
+ int projectImageTotal; /* size of projectImages array */
+ int imaContextIndex; /* current image, use for context switching */
float (*projectVertScreenCos)[3]; /* verts projected into floating point screen space */
/* options for projection painting */
- short projectIsOcclude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/
+ short projectIsOcclude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/
short projectIsBackfaceCull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */
short projectIsOrtho;
#ifndef PROJ_DEBUG_NOSEAMBLEED
@@ -424,6 +430,7 @@ static void BaryCentricWeightsSimple2f(float v1[2], float v2[2], float v3[2], fl
w[1]/=wtot;
w[2]/=wtot;
} else {
+ printf("WATCH oUT ZAREA FACE\n");
w[0] = w[1] = w[2] = 1.0/3.0; /* dummy values for zero area face */
}
}
@@ -624,6 +631,7 @@ static int project_bucket_point_occluded(ProjectPaintState *ps, int bucket_index
}
if (isect_ret==1) {
+#if 0
/* Cheap Optimization!
* This function runs for every UV Screen pixel,
* therefor swapping the swapping the faces for this buckets list helps because
@@ -639,7 +647,7 @@ static int project_bucket_point_occluded(ProjectPaintState *ps, int bucket_index
} /*else {
printf("first hit %d\n", face_index);
}*/
-
+#endif
return 1;
}
}
@@ -654,7 +662,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[2], float p2[2], float y_level, float *x_isect)
+static int line_isect_y(float p1[2], float p2[2], float y_level, float *x_isect)
{
if (y_level==p1[1]) {
*x_isect = p1[0];
@@ -676,6 +684,28 @@ static int project_scanline_isect(float p1[2], float p2[2], float y_level, float
}
}
+static int line_isect_x(float p1[2], float p2[2], float x_level, float *y_isect)
+{
+ if (x_level==p1[0]) {
+ *y_isect = p1[1];
+ return ISECT_TRUE_P1;
+ }
+ if (x_level==p2[0]) {
+ *y_isect = p2[1];
+ return ISECT_TRUE_P2;
+ }
+
+ if (p1[0] > x_level && p2[0] < x_level) {
+ *y_isect = (p2[1]*(p1[0]-x_level) + p1[1]*(x_level-p2[0])) / (p1[0]-p2[0]);
+ return ISECT_TRUE;
+ } else if (p1[0] < x_level && p2[0] > x_level) {
+ *y_isect = (p2[1]*(x_level-p1[0]) + p1[1]*(p2[0]-x_level)) / (p2[0]-p1[0]);
+ return ISECT_TRUE;
+ } else {
+ return 0;
+ }
+}
+
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
@@ -687,9 +717,9 @@ static int project_face_scanline(ProjectScanline *sc, float y_level, float v1[2]
int i4=0, i_mid=0;
float xi1, xi2, xi3, xi4, xi_mid;
- i1 = project_scanline_isect(v1, v2, y_level, &xi1);
+ i1 = line_isect_y(v1, v2, y_level, &xi1);
if (i1 != ISECT_TRUE_P2) /* rare cases we could be on the line, in these cases we dont want to intersect with the same point twice */
- i2 = project_scanline_isect(v2, v3, y_level, &xi2);
+ i2 = line_isect_y(v2, v3, y_level, &xi2);
if (i1 && i2) { /* both the first 2 edges intersect, this means the second half of the quad wont intersect */
sc->v[0] = 0;
@@ -700,9 +730,9 @@ static int project_face_scanline(ProjectScanline *sc, float y_level, float v1[2]
totscanlines = 1;
} else {
if (i2 != ISECT_TRUE_P2)
- i3 = project_scanline_isect(v3, v4, y_level, &xi3);
+ i3 = line_isect_y(v3, v4, y_level, &xi3);
if (i1 != ISECT_TRUE_P1 && i3 != ISECT_TRUE_P2)
- i4 = project_scanline_isect(v4, v1, y_level, &xi4);
+ i4 = line_isect_y(v4, v1, y_level, &xi4);
if (i3 && i4) { /* second 2 edges only intersect, same as above */
sc->v[0] = 0;
@@ -715,7 +745,7 @@ static int project_face_scanline(ProjectScanline *sc, float y_level, float v1[2]
/* OK - we have a not-so-simple case, both sides of the quad intersect.
* Will need to have 2 scanlines */
if ((i1||i2) && (i3||i4)) {
- i_mid = project_scanline_isect(v1, v3, y_level, &xi_mid);
+ i_mid = line_isect_y(v1, v3, y_level, &xi_mid);
/* it would be very rare this would be false, but possible */
sc->v[0] = 0;
sc->v[1] = 1;
@@ -737,11 +767,11 @@ static int project_face_scanline(ProjectScanline *sc, float y_level, float v1[2]
} else { /* triangle */
int i = 0;
- i1 = project_scanline_isect(v1, v2, y_level, &sc->x_limits[0]);
+ i1 = line_isect_y(v1, v2, y_level, &sc->x_limits[0]);
if (i1) i++;
if (i1 != ISECT_TRUE_P2) {
- i2 = project_scanline_isect(v2, v3, y_level, &sc->x_limits[i]);
+ i2 = line_isect_y(v2, v3, y_level, &sc->x_limits[i]);
if (i2) i++;
}
@@ -750,7 +780,7 @@ static int project_face_scanline(ProjectScanline *sc, float y_level, float v1[2]
if (i!=2) {
/* if we are here then this really should not fail since 2 edges MUST intersect */
if (i1 != ISECT_TRUE_P1 && i2 != ISECT_TRUE_P2) {
- i3 = project_scanline_isect(v3, v1, y_level, &sc->x_limits[i]);
+ i3 = line_isect_y(v3, v1, y_level, &sc->x_limits[i]);
if (i3) i++;
}
@@ -778,7 +808,8 @@ static int cmp_uv(float vec2a[2], float vec2b[2])
#ifndef PROJ_DEBUG_NOSEAMBLEED
-static int check_seam(ProjectPaintState *ps, int orig_face, int orig_i1_fidx, int orig_i2_fidx)
+/* TODO - set the seam flag on the other face to avoid double lookups */
+static int check_seam(ProjectPaintState *ps, int orig_face, int orig_i1_fidx, int orig_i2_fidx, int *other_face, int *orig_fidx)
{
LinkNode *node;
int face_index;
@@ -814,15 +845,17 @@ static int check_seam(ProjectPaintState *ps, int orig_face, int orig_i1_fidx, in
if (i2_fidx != -1) {
/* This IS an adjacent face!, now lets check if the UVs are ok */
+
+
tf = ps->dm_mtface + face_index;
- /* first test if they have the same image */
- if (orig_tf->tpage != tf->tpage) {
- // printf("SEAM (IMAGE DIFF)\n");
- return 1;
- }
+ /* set up the other face */
+ *other_face = face_index;
+ *orig_fidx = (i1_fidx < i2_fidx) ? i1_fidx : i2_fidx;
- if ( cmp_uv(orig_tf->uv[orig_i1_fidx], tf->uv[i1_fidx]) &&
+ /* first test if they have the same image */
+ if ( (orig_tf->tpage == tf->tpage) &&
+ cmp_uv(orig_tf->uv[orig_i1_fidx], tf->uv[i1_fidx]) &&
cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]) )
{
// printf("SEAM (NONE)\n");
@@ -836,25 +869,10 @@ static int check_seam(ProjectPaintState *ps, int orig_face, int orig_i1_fidx, in
}
}
// printf("SEAM (NO FACE)\n");
+ *other_face = -1;
return 1;
}
-static void project_face_seams_init(ProjectPaintState *ps, int face_index, int is_quad)
-{
- if (is_quad) {
- ps->projectFaceFlags[face_index] |=
- (check_seam(ps, face_index, 0,1) ? PROJ_FACE_SEAM1 : 0) |
- (check_seam(ps, face_index, 1,2) ? PROJ_FACE_SEAM2 : 0) |
- (check_seam(ps, face_index, 2,3) ? PROJ_FACE_SEAM3 : 0) |
- (check_seam(ps, face_index, 3,0) ? PROJ_FACE_SEAM4 : 0);
- } else {
- ps->projectFaceFlags[face_index] |=
- (check_seam(ps, face_index, 0,1) ? PROJ_FACE_SEAM1 : 0) |
- (check_seam(ps, face_index, 1,2) ? PROJ_FACE_SEAM2 : 0) |
- (check_seam(ps, face_index, 2,0) ? PROJ_FACE_SEAM3 : 0);
- }
-}
-#endif // PROJ_DEBUG_NOSEAMBLEED
static float angleToLength(float angle)
{
@@ -1016,6 +1034,38 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], float sc
}
}
+/*
+ * Be tricky with flags, first 4 bits are PROJ_FACE_SEAM1 to 4, last 4 bits are PROJ_FACE_NOSEAM1 to 4
+ * 1<<i - where i is (0-3)
+ */
+static void project_face_seams_init(ProjectPaintState *ps, int face_index, int is_quad)
+{
+ int other_face, other_fidx; /* vars for the other face, we also set its flag */
+ int fidx1, fidx2;
+
+ fidx1 = is_quad ? 3 : 2;
+ do {
+ if (is_quad)
+ fidx2 = (fidx1==3) ? 0 : fidx1+1; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) */
+ else
+ fidx2 = (fidx1==2) ? 0 : fidx1+1; /* next fidx in the face (0,1,2) -> (1,2,0) */
+
+ if ((ps->projectFaceSeamFlags[face_index] & (1<<fidx1|16<<fidx1)) == 0) {
+ if (check_seam(ps, face_index, fidx1,fidx2, &other_face, &other_fidx)) {
+ ps->projectFaceSeamFlags[face_index] |= 1<<fidx1;
+ if (other_face != -1)
+ ps->projectFaceSeamFlags[other_face] |= 1<<other_fidx;
+ } else {
+ ps->projectFaceSeamFlags[face_index] |= 16<<fidx1;
+ if (other_face != -1)
+ ps->projectFaceSeamFlags[other_face] |= 16<<other_fidx; /* second 4 bits for disabled */
+ }
+ }
+ } while (fidx1--);
+}
+#endif // PROJ_DEBUG_NOSEAMBLEED
+
+
/* TODO - move to arithb.c */
/* little sister we only need to know lambda */
@@ -1063,29 +1113,22 @@ static screen_px_from_persp(
}
-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[2], int x, int y, int face_index, float pixelScreenCo[4])
+static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, int x, int y, int bucket_index, int face_index, float pixelScreenCo[4])
{
- int bucket_index;
-
- // printf("adding px (%d %d), (%f %f)\n", x,y,uv[0],uv[1]);
-
ProjectPixel *projPixel;
- bucket_index = project_paint_BucketOffsetSafe(ps, pixelScreenCo);
+ // printf("adding px (%d %d), (%f %f)\n", x,y,uv[0],uv[1]);
- /* even though it should be clamped, in some cases it can still run over */
- if (bucket_index==-1)
- return;
/* Use viewMin2D to make (0,0) the bottom left of the bounds
* Then this can be used to index the bucket array */
/* Is this UV visible from the view? - raytrace */
+ /* screenco_pickface is less complex, use for testing */
+ //if (screenco_pickface(ps, pixelScreenCo, w, &side) == face_index) {
if (ps->projectIsOcclude==0 || !project_bucket_point_occluded(ps, bucket_index, face_index, pixelScreenCo)) {
/* done with view3d_project_float inline */
if (ps->tool==PAINT_TOOL_CLONE) {
@@ -1118,9 +1161,6 @@ static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, float
/* screenspace unclamped */
-
-
-
#ifdef PROJ_DEBUG_PAINT
projPixel->pixel[1] = 0;
#endif
@@ -1134,7 +1174,146 @@ static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, float
}
}
-static void project_paint_face_init(ProjectPaintState *ps, int face_index, ImBuf *ibuf)
+static void uvpixel_rect_intersect(int min_target[2], int max_target[2], int min_a[2], int max_a[2], int min_b[2], int max_b[2])
+{
+ min_target[0] = MAX2(min_a[0], min_b[0]);
+ min_target[1] = MAX2(min_a[1], min_b[1]);
+
+ max_target[0] = MIN2(max_a[0], max_b[0]);
+ max_target[1] = MIN2(max_a[1], max_b[1]);
+}
+
+static int line_clip_rect2f(float rect[4], float l1[2], float l2[2], float l1_clip[2], float l2_clip[2])
+{
+ float isect;
+ short ok1 = 0;
+ short ok2 = 0;
+
+ /* are either of the points inside the rectangle ? */
+ if ( l1[1] >= rect[PROJ_BUCKET_BOTTOM] && l1[1] <= rect[PROJ_BUCKET_TOP] &&
+ l1[0] >= rect[PROJ_BUCKET_LEFT] && l1[0] <= rect[PROJ_BUCKET_RIGHT]
+ ) {
+ VECCOPY2D(l1_clip, l1);
+ ok1 = 1;
+ }
+
+ if ( l2[1] >= rect[PROJ_BUCKET_BOTTOM] && l2[1] <= rect[PROJ_BUCKET_TOP] &&
+ l2[0] >= rect[PROJ_BUCKET_LEFT] && l2[0] <= rect[PROJ_BUCKET_RIGHT]
+ ) {
+ VECCOPY2D(l2_clip, l2);
+ ok2 = 1;
+ }
+
+ /* line inside rect */
+ if (ok1 && ok2) {
+ return 1;
+ }
+
+ /* top/bottom */
+ if (line_isect_y(l1,l2, rect[PROJ_BUCKET_BOTTOM], &isect) && (isect > rect[PROJ_BUCKET_LEFT]) && (isect < rect[PROJ_BUCKET_RIGHT])) {
+ if (l1[1] < l2[1]) { /* line 1 is outside */
+ l1_clip[0] = isect;
+ l1_clip[1] = rect[PROJ_BUCKET_BOTTOM];
+ ok1 = 1;
+ } else {
+ l2_clip[0] = isect;
+ l2_clip[1] = rect[PROJ_BUCKET_BOTTOM];
+ ok2 = 2;
+ }
+ }
+ if (line_isect_y(l1,l2, rect[PROJ_BUCKET_TOP], &isect) && (isect > rect[PROJ_BUCKET_LEFT]) && (isect < rect[PROJ_BUCKET_RIGHT])) {
+ if (l1[1] > l2[1]) { /* line 1 is outside */
+ l1_clip[0] = isect;
+ l1_clip[1] = rect[PROJ_BUCKET_TOP];
+ ok1 = 1;
+ } else {
+ l2_clip[0] = isect;
+ l2_clip[1] = rect[PROJ_BUCKET_TOP];
+ ok2 = 2;
+ }
+ }
+
+ /* left/right */
+ if (line_isect_x(l1,l2, rect[PROJ_BUCKET_LEFT], &isect) && (isect > rect[PROJ_BUCKET_BOTTOM]) && (isect < rect[PROJ_BUCKET_TOP])) {
+ if (l1[0] < l2[0]) { /* line 1 is outside */
+ l1_clip[0] = rect[PROJ_BUCKET_LEFT];
+ l1_clip[1] = isect;
+ ok1 = 1;
+ } else {
+ l2_clip[0] = rect[PROJ_BUCKET_LEFT];
+ l2_clip[1] = isect;
+ ok2 = 2;
+ }
+ }
+ if (line_isect_x(l1,l2, rect[PROJ_BUCKET_RIGHT], &isect) && (isect > rect[PROJ_BUCKET_BOTTOM]) && (isect < rect[PROJ_BUCKET_TOP])) {
+ if (l1[0] > l2[0]) { /* line 1 is outside */
+ l1_clip[0] = rect[PROJ_BUCKET_RIGHT];
+ l1_clip[1] = isect;
+ ok1 = 1;
+ } else {
+ l2_clip[0] = rect[PROJ_BUCKET_RIGHT];
+ l2_clip[1] = isect;
+ ok2 = 2;
+ }
+ }
+
+ if (ok1 && ok2) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+
+/* scale the quad & tri about its center
+ * scaling by 0.99999 is used for getting fake UV pixel coords that are on the
+ * edge of the face but slightly inside it occlusion tests dont return hits on adjacent faces */
+static void scale_quad(float *origCos[4], float insetCos[4][3], float inset)
+{
+ float cent[3];
+ cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0] + origCos[3][0]) / 4.0;
+ cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1] + origCos[3][1]) / 4.0;
+ cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2] + origCos[3][2]) / 4.0;
+
+ VecSubf(insetCos[0], origCos[0], cent);
+ VecSubf(insetCos[1], origCos[1], cent);
+ VecSubf(insetCos[2], origCos[2], cent);
+ VecSubf(insetCos[3], origCos[3], cent);
+
+ VecMulf(insetCos[0], inset);
+ VecMulf(insetCos[1], inset);
+ VecMulf(insetCos[2], inset);
+ VecMulf(insetCos[3], inset);
+
+ VecAddf(insetCos[0], insetCos[0], cent);
+ VecAddf(insetCos[1], insetCos[1], cent);
+ VecAddf(insetCos[2], insetCos[2], cent);
+ VecAddf(insetCos[3], insetCos[3], cent);
+}
+
+static void scale_tri(float *origCos[4], float insetCos[4][3], float inset)
+{
+ float cent[3];
+ cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0]) / 3.0;
+ cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1]) / 3.0;
+ cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2]) / 3.0;
+
+ VecSubf(insetCos[0], origCos[0], cent);
+ VecSubf(insetCos[1], origCos[1], cent);
+ VecSubf(insetCos[2], origCos[2], cent);
+
+ VecMulf(insetCos[0], inset);
+ VecMulf(insetCos[1], inset);
+ VecMulf(insetCos[2], inset);
+
+ VecAddf(insetCos[0], insetCos[0], cent);
+ VecAddf(insetCos[1], insetCos[1], cent);
+ VecAddf(insetCos[2], insetCos[2], cent);
+}
+
+/**/
+static void project_paint_face_init(ProjectPaintState *ps, int bucket_index, int face_index, float bucket_bounds[4], ImBuf *ibuf)
{
/* Projection vars, to get the 3D locations into screen space */
@@ -1147,277 +1326,249 @@ static void project_paint_face_init(ProjectPaintState *ps, int face_index, ImBuf
float uv[2]; /* Image floating point UV - same as x,y but from 0.0-1.0 */
int min_px[2], max_px[2]; /* UV Bounds converted to int's for pixel */
- float *v1co, *v2co, *v3co; /* for convenience only, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
+ int min_px_tf[2], max_px_tf[2]; /* UV Bounds converted to int's for pixel */
+ int min_px_bucket[2][2], max_px_bucket[2][2]; /* Bucket Bounds converted to int's for pixel */
+ float *v1coSS, *v2coSS, *v3coSS, *v4coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
+ float *v1co, *v2co, *v3co; /* vert co */
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], pixelScreenCoXMin[4], pixelScreenCoXMax[4];
int i, j;
+ /* vars for getting uvspace bounds */
+ float bucket_bounds_uv[2] [4][2]; /* bucket bounds in UV space so we can init pixels only for this face, */
+ float w[3];
+ int i1,i2,i3;
+
/* scanlines since quads can have 2 triangles intersecting the same vertical location */
#ifndef PROJ_DEBUG_NOSCANLINE
ProjectScanline scanlines[2];
ProjectScanline *sc;
int totscanlines; /* can only be 1 or 2, oh well */
#endif
-
- if (!uv_image_rect(tf->uv[0], tf->uv[1], tf->uv[2], tf->uv[3], min_px, max_px, ibuf->x, ibuf->y, mf->v4))
- return;
-
-#ifndef PROJ_DEBUG_NOSEAMBLEED
- /* detect UV seams so we can bleed */
- if (ps->projectSeamBleed > 0.0)
- project_face_seams_init(ps, face_index, mf->v4);
-#endif
-
- for (y = min_px[1]; y < max_px[1]; y++) {
- uv[1] = (((float)y)+0.5) / (float)ibuf->y; /* TODO - this is not pixel aligned correctly */
-
-#ifndef PROJ_DEBUG_NOSCANLINE
- totscanlines = project_face_scanline(scanlines, uv[1], tf->uv[0], tf->uv[1], tf->uv[2], mf->v4 ? tf->uv[3]:NULL);
-
- /* Loop over scanlines a bit silly since there can only be 1 or 2, but its easier then having tri/quad spesific functions */
- for (j=0, sc=scanlines; j<totscanlines; j++, sc++) {
-
- min_px[0] = (int)((ibuf->x * sc->x_limits[0])+0.5);
- max_px[0] = (int)((ibuf->x * sc->x_limits[1])+0.5);
- CLAMP(min_px[0], 0, ibuf->x);
- CLAMP(max_px[0], 0, ibuf->x);
-
- uv1co = tf->uv[sc->v[0]];
- uv2co = tf->uv[sc->v[1]];
- uv3co = tf->uv[sc->v[2]];
-
- if (ps->projectIsOrtho) {
- v1co = ps->projectVertScreenCos[ (*(&mf->v1 + sc->v[0])) ];
- v2co = ps->projectVertScreenCos[ (*(&mf->v1 + sc->v[1])) ];
- v3co = ps->projectVertScreenCos[ (*(&mf->v1 + sc->v[2])) ];
-
- for (x = min_px[0]; x < max_px[0]; x++) {
- uv[0] = (((float)x)+0.5) / (float)ibuf->x;
- screen_px_from_ortho(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
- project_paint_uvpixel_init(ps, ibuf, uv, x,y,face_index, pixelScreenCo);
- }
- } else {
- v1co = ps->dm_mvert[ (*(&mf->v1 + sc->v[0])) ].co;
- v2co = ps->dm_mvert[ (*(&mf->v1 + sc->v[1])) ].co;
- v3co = ps->dm_mvert[ (*(&mf->v1 + sc->v[2])) ].co;
-
- for (x = min_px[0]; x < max_px[0]; x++) {
- uv[0] = (((float)x)+0.5) / (float)ibuf->x;
- screen_px_from_persp(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
- project_paint_uvpixel_init(ps, ibuf, uv, x,y,face_index, pixelScreenCo);
- }
- }
- }
-#else /* slow, non scanline method */
-
- /* mainly for debuggung scanline, use point-in-tri for every x/y test */
- /* at the moment only works with ortho triangles */
- uv1co = tf->uv[0];
- uv2co = tf->uv[1];
- uv3co = tf->uv[2];
-
- if (ps->projectIsOrtho) {
- v1co = ps->projectVertScreenCos[ mf->v1 ];
- v2co = ps->projectVertScreenCos[ mf->v2 ];
- v3co = ps->projectVertScreenCos[ mf->v3 ];
-
- for (x = min_px[0]; x < max_px[0]; x++) {
- uv[0] = (((float)x)+0.5) / (float)ibuf->x;
- if (IsectPT2Df(uv, uv1co, uv2co, uv3co)) {
- screen_px_from_ortho(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
- project_paint_uvpixel_init(ps, ibuf, uv, x,y,face_index, pixelScreenCo);
- }
-
- }
+ i = mf->v4 ? 1:0;
+ do {
+ if (i==1) {
+ i1=0; i2=1; i3=2;
} else {
- /*
- v1co = ps->dm_mvert[ (*(&mf->v1 + sc->v[0])) ].co;
- v2co = ps->dm_mvert[ (*(&mf->v1 + sc->v[1])) ].co;
- v3co = ps->dm_mvert[ (*(&mf->v1 + sc->v[2])) ].co;
-
- for (x = min_px[0]; x < max_px[0]; x++) {
- uv[0] = (((float)x)+0.5) / (float)ibuf->x;
- screen_px_from_persp(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
- project_paint_uvpixel_init(ps, sc, ibuf, uv, x,y,face_index, pixelScreenCo);
- }
- */
+ i1=0; i2=2; i3=3;
}
-#endif
- }
+
+ uv1co = tf->uv[i1];
+ uv2co = tf->uv[i2];
+ uv3co = tf->uv[i3];
-
-#ifndef PROJ_DEBUG_NOSCANLINE
-#ifndef PROJ_DEBUG_NOSEAMBLEED
- /* Pretty much a copy of above, except fill in seams if we have any */
- if (ps->projectFaceFlags[face_index] & (PROJ_FACE_SEAM1|PROJ_FACE_SEAM2|PROJ_FACE_SEAM3|PROJ_FACE_SEAM4)) {
- float outset_uv[4][2]; /* expanded UV's */
- float insetCos[4][3]; /* expanded UV's */
- float cent[3];
- float *uv_seam_quads[4][4];
- float *edge_verts[4][2];
- float pixelScreenCo[3];
- float fac;
- int totuvseamquads = 0;
+ v1coSS = ps->projectVertScreenCos[ (*(&mf->v1 + i1)) ];
+ v2coSS = ps->projectVertScreenCos[ (*(&mf->v1 + i2)) ];
+ v3coSS = ps->projectVertScreenCos[ (*(&mf->v1 + i3)) ];
- if (ps->projectIsOrtho) {
- VECCOPY(insetCos[0], ps->projectVertScreenCos[ mf->v1 ]);
- VECCOPY(insetCos[1], ps->projectVertScreenCos[ mf->v2 ]);
- VECCOPY(insetCos[2], ps->projectVertScreenCos[ mf->v3 ]);
- if (mf->v4)
- VECCOPY(insetCos[3], ps->projectVertScreenCos[ mf->v4 ]);
- } else {
- VECCOPY(insetCos[0], ps->dm_mvert[ mf->v1 ].co);
- VECCOPY(insetCos[1], ps->dm_mvert[ mf->v2 ].co);
- VECCOPY(insetCos[2], ps->dm_mvert[ mf->v3 ].co);
- if (mf->v4)
- VECCOPY(insetCos[3], ps->dm_mvert[ mf->v4 ].co);
+ if (ps->projectIsOrtho==0) {
+ v1co = ps->dm_mvert[ (*(&mf->v1 + i1)) ].co;
+ v2co = ps->dm_mvert[ (*(&mf->v1 + i2)) ].co;
+ v3co = ps->dm_mvert[ (*(&mf->v1 + i3)) ].co;
}
-
- if (mf->v4) {
- cent[0] = (insetCos[0][0] + insetCos[1][0] + insetCos[2][0] + insetCos[3][0]) / 4.0;
- cent[1] = (insetCos[0][1] + insetCos[1][1] + insetCos[2][1] + insetCos[3][1]) / 4.0;
- cent[2] = (insetCos[0][2] + insetCos[1][2] + insetCos[2][2] + insetCos[3][2]) / 4.0;
-
- } else {
- cent[0] = (insetCos[0][0] + insetCos[1][0] + insetCos[2][0]) / 3.0;
- cent[1] = (insetCos[0][1] + insetCos[1][1] + insetCos[2][1]) / 3.0;
- cent[2] = (insetCos[0][2] + insetCos[1][2] + insetCos[2][2]) / 3.0;
- }
+ /* get the UV space bounding box */
+ uv[0] = bucket_bounds[PROJ_BUCKET_RIGHT];
+ uv[1] = bucket_bounds[PROJ_BUCKET_BOTTOM];
+ BaryCentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
+ bucket_bounds_uv[i][0][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
+ bucket_bounds_uv[i][0][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
- VecSubf(insetCos[0], insetCos[0], cent);
- VecSubf(insetCos[1], insetCos[1], cent);
- VecSubf(insetCos[2], insetCos[2], cent);
- if (mf->v4)
- VecSubf(insetCos[3], insetCos[3], cent);
+ //uv[0] = bucket_bounds[PROJ_BUCKET_RIGHT]; // set above
+ uv[1] = bucket_bounds[PROJ_BUCKET_TOP];
+ BaryCentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
+ bucket_bounds_uv[i][1][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
+ bucket_bounds_uv[i][1][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
- VecMulf(insetCos[0], 1.0 - 0.0001);
- VecMulf(insetCos[1], 1.0 - 0.0001);
- VecMulf(insetCos[2], 1.0 - 0.0001);
- if (mf->v4)
- VecMulf(insetCos[3], 1.0 - 0.0001);
- VecAddf(insetCos[0], insetCos[0], cent);
- VecAddf(insetCos[1], insetCos[1], cent);
- VecAddf(insetCos[2], insetCos[2], cent);
- if (mf->v4)
- VecAddf(insetCos[3], insetCos[3], cent);
- /* done with inset */
+ uv[0] = bucket_bounds[PROJ_BUCKET_LEFT];
+ //uv[1] = bucket_bounds[PROJ_BUCKET_TOP]; // set above
+ BaryCentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
+ bucket_bounds_uv[i][2][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
+ bucket_bounds_uv[i][2][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
- uv_image_outset(tf->uv, outset_uv, ps->projectSeamBleed, ibuf->x, ibuf->y, mf->v4);
+ //uv[0] = bucket_bounds[PROJ_BUCKET_LEFT]; // set above
+ uv[1] = bucket_bounds[PROJ_BUCKET_BOTTOM];
+ BaryCentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
+ bucket_bounds_uv[i][3][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
+ bucket_bounds_uv[i][3][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
- if (ps->projectFaceFlags[face_index] & PROJ_FACE_SEAM1) {
- uv_seam_quads[totuvseamquads][0] = tf->uv[0];
- uv_seam_quads[totuvseamquads][1] = tf->uv[1];
- uv_seam_quads[totuvseamquads][2] = outset_uv[1];
- uv_seam_quads[totuvseamquads][3] = outset_uv[0];
- edge_verts[totuvseamquads][0] = insetCos[0]; //ps->projectVertScreenCos[ mf->v1 ];
- edge_verts[totuvseamquads][1] = insetCos[1]; //ps->projectVertScreenCos[ mf->v2 ];
- totuvseamquads++;
+ //printf("Bounds: %f | %f | %f | %f\n", bucket_bounds[0], bucket_bounds[1], bucket_bounds[2], bucket_bounds[3]);
+
+ if ( uv_image_rect(uv1co, uv2co, uv3co, NULL, min_px_tf, max_px_tf, ibuf->x, ibuf->y, 0) &&
+ uv_image_rect(bucket_bounds_uv[i][0], bucket_bounds_uv[i][1], bucket_bounds_uv[i][2], bucket_bounds_uv[i][3], min_px_bucket[i], max_px_bucket[i], ibuf->x, ibuf->y, 1) )
+ {
+
+ uvpixel_rect_intersect(min_px, max_px, min_px_bucket[i], max_px_bucket[i], min_px_tf, max_px_tf);
+
+ /* clip face and */
+
+
+ for (y = min_px[1]; y < max_px[1]; y++) {
+ uv[1] = (((float)y)+0.5) / (float)ibuf->y; /* TODO - this is not pixel aligned correctly */
+ for (x = min_px[0]; x < max_px[0]; x++) {
+ uv[0] = (((float)x)+0.5) / (float)ibuf->x;
+
+ /* test we're inside uvspace bucket and triangle bounds */
+ if ( IsectPQ2Df(uv, bucket_bounds_uv[i][0], bucket_bounds_uv[i][1], bucket_bounds_uv[i][2], bucket_bounds_uv[i][3]) &&
+ IsectPT2Df(uv, uv1co, uv2co, uv3co) ) {
+
+ if (ps->projectIsOrtho) {
+ screen_px_from_ortho(ps, uv, v1coSS,v2coSS,v3coSS, uv1co,uv2co,uv3co, pixelScreenCo);
+ } else {
+ screen_px_from_persp(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
+ }
+
+ project_paint_uvpixel_init(ps, ibuf, x,y, bucket_index, face_index, pixelScreenCo);
+ }
+ }
+ }
}
+ } while(i--);
+
+ if (ps->projectSeamBleed > 0.0) {
- if (ps->projectFaceFlags[face_index] & PROJ_FACE_SEAM2) {
- uv_seam_quads[totuvseamquads][0] = tf->uv[1];
- uv_seam_quads[totuvseamquads][1] = tf->uv[2];
- uv_seam_quads[totuvseamquads][2] = outset_uv[2];
- uv_seam_quads[totuvseamquads][3] = outset_uv[1];
- edge_verts[totuvseamquads][0] = insetCos[1]; //ps->projectVertScreenCos[ mf->v2 ];
- edge_verts[totuvseamquads][1] = insetCos[2]; //ps->projectVertScreenCos[ mf->v3 ];
- totuvseamquads++;
+ int flag = ps->projectFaceSeamFlags[face_index];
+
+ /* are any of our edges un-initialized? */
+ if ((flag & (PROJ_FACE_SEAM1|PROJ_FACE_NOSEAM1))==0 ||
+ (flag & (PROJ_FACE_SEAM2|PROJ_FACE_NOSEAM2))==0 ||
+ (flag & (PROJ_FACE_SEAM3|PROJ_FACE_NOSEAM3))==0 ||
+ (flag & (PROJ_FACE_SEAM4|PROJ_FACE_NOSEAM4))==0
+ ) {
+ project_face_seams_init(ps, face_index, mf->v4);
+ flag = ps->projectFaceSeamFlags[face_index];
+ //printf("seams - %d %d %d %d\n", flag&PROJ_FACE_SEAM1, flag&PROJ_FACE_SEAM2, flag&PROJ_FACE_SEAM3, flag&PROJ_FACE_SEAM4);
}
- if (mf->v4) {
- if (ps->projectFaceFlags[face_index] & PROJ_FACE_SEAM3) {
- uv_seam_quads[totuvseamquads][0] = tf->uv[2];
- uv_seam_quads[totuvseamquads][1] = tf->uv[3];
- uv_seam_quads[totuvseamquads][2] = outset_uv[3];
- uv_seam_quads[totuvseamquads][3] = outset_uv[2];
- edge_verts[totuvseamquads][0] = insetCos[2]; //ps->projectVertScreenCos[ mf->v3 ];
- edge_verts[totuvseamquads][1] = insetCos[3]; //ps->projectVertScreenCos[ mf->v4 ];
- totuvseamquads++;
- }
- if (ps->projectFaceFlags[face_index] & PROJ_FACE_SEAM4) {
- uv_seam_quads[totuvseamquads][0] = tf->uv[3];
- uv_seam_quads[totuvseamquads][1] = tf->uv[0];
- uv_seam_quads[totuvseamquads][2] = outset_uv[0];
- uv_seam_quads[totuvseamquads][3] = outset_uv[3];
- edge_verts[totuvseamquads][0] = insetCos[3]; //ps->projectVertScreenCos[ mf->v4 ];
- edge_verts[totuvseamquads][1] = insetCos[0]; //ps->projectVertScreenCos[ mf->v1 ];
- totuvseamquads++;
+ if (flag & (PROJ_FACE_SEAM1|PROJ_FACE_SEAM2|PROJ_FACE_SEAM3|PROJ_FACE_SEAM4)) {
+ /* we have a seam - deal with it! */
+
+ /* Now create new UV's for the seam face */
+ float (*outset_uv)[2];
+ float insetCos[4][3]; /* expanded UV's */
+ float cent[3];
+ float *uv_seam_quads[4][4];
+ float *edge_verts_inset[4][2];
+ float *edge_verts[4][2];
+ float fac;
+ float *vCoSS[4]; /* vertex screenspace coords */
+
+ float bucket_clip_edges[4][2][2]; /* store the screenspace coords of the face, clipped by the bucket's screen aligned rectangle */
+ int totuvseamquads = 0;
+ 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 */
+
+ outset_uv = ps->projectFaceSeamUVs[face_index];
+
+ if (outset_uv[0][0]==MAXFLOAT) /* first time initialize */
+ uv_image_outset(tf->uv, outset_uv, ps->projectSeamBleed, ibuf->x, ibuf->y, mf->v4);
+
+ vCoSS[0] = ps->projectVertScreenCos[ mf->v1 ];
+ vCoSS[1] = ps->projectVertScreenCos[ mf->v2 ];
+ vCoSS[2] = ps->projectVertScreenCos[ mf->v3 ];
+ if (mf->v4) {
+ vCoSS[3] = ps->projectVertScreenCos[ mf->v4 ];
+ scale_quad(vCoSS, insetCos, 0.99999);
+ } else {
+ scale_tri(vCoSS, insetCos, 0.99999);
}
- } else {
- if (ps->projectFaceFlags[face_index] & PROJ_FACE_SEAM3) {
- uv_seam_quads[totuvseamquads][0] = tf->uv[2];
- uv_seam_quads[totuvseamquads][1] = tf->uv[0];
- uv_seam_quads[totuvseamquads][2] = outset_uv[0];
- uv_seam_quads[totuvseamquads][3] = outset_uv[2];
- edge_verts[totuvseamquads][0] = insetCos[2]; //ps->projectVertScreenCos[ mf->v3 ];
- edge_verts[totuvseamquads][1] = insetCos[0]; //ps->projectVertScreenCos[ mf->v1 ];
- totuvseamquads++;
+
+ for (fidx1 = 0; fidx1 < (mf->v4 ? 4 : 3); fidx1++) {
+ if (mf->v4) fidx2 = (fidx1==3) ? 0 : fidx1+1; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) */
+ else fidx2 = (fidx1==2) ? 0 : fidx1+1; /* next fidx in the face (0,1,2) -> (1,2,0) */
+
+ if ( (ps->projectFaceSeamFlags[face_index] & (1<<fidx1) ) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */
+ line_clip_rect2f(bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[totuvseamquads][0], bucket_clip_edges[totuvseamquads][1])
+ ) {
+ uv_seam_quads[totuvseamquads][0] = tf->uv[fidx1];
+ uv_seam_quads[totuvseamquads][1] = tf->uv[fidx2];
+ uv_seam_quads[totuvseamquads][2] = outset_uv[fidx2];
+ uv_seam_quads[totuvseamquads][3] = outset_uv[fidx1];
+ edge_verts_inset[totuvseamquads][0] = insetCos[fidx1]; //ps->projectVertScreenCos[ mf->v3 ];
+ edge_verts_inset[totuvseamquads][1] = insetCos[fidx2]; //ps->projectVertScreenCos[ mf->v1 ];
+ edge_verts[totuvseamquads][0] = vCoSS[fidx1];
+ edge_verts[totuvseamquads][1] = vCoSS[fidx2];
+ totuvseamquads++;
+ }
}
- }
-
- for (i=0; i< totuvseamquads; i++) { /* loop over our seams */
- if (uv_image_rect(uv_seam_quads[i][0], uv_seam_quads[i][1], uv_seam_quads[i][2], uv_seam_quads[i][3], min_px, max_px, ibuf->x, ibuf->y, 1)) {
+
+
+ for (i=0; i< totuvseamquads; i++) { /* loop over our seams */
- for (y = min_px[1]; y < max_px[1]; y++) {
- uv[1] = (((float)y)+0.5) / (float)ibuf->y;
-
- totscanlines = project_face_scanline(scanlines, uv[1], uv_seam_quads[i][0], uv_seam_quads[i][1], uv_seam_quads[i][2], uv_seam_quads[i][3]);
-
- /* Loop over scanlines a bit silly since there can only be 1 or 2, but its easier then having tri/quad spesific functions */
- for (j=0, sc=scanlines; j<totscanlines; j++, sc++) {
-
- min_px[0] = (int)((ibuf->x * sc->x_limits[0])+0.5);
- max_px[0] = (int)((ibuf->x * sc->x_limits[1])+0.5);
- CLAMP(min_px[0], 0, ibuf->x);
- CLAMP(max_px[0], 0, ibuf->x);
+
+ /* make a quad spanning the subsection of the face the bucket intersects with */
+ float seam_subsection[4][2];
+ float fac1, fac2, ftot;
+ float edge_verts_inset_clip[2][3];
+
+ ftot = Vec2Lenf(edge_verts[i][0], edge_verts[i][1]);
+ fac1 = Vec2Lenf(edge_verts[i][0], bucket_clip_edges[i][0]) / ftot;
+ fac2 = Vec2Lenf(edge_verts[i][0], bucket_clip_edges[i][1]) / ftot;
+
+ Vec2Lerpf(seam_subsection[0], uv_seam_quads[i][0], uv_seam_quads[i][1], fac1);
+ Vec2Lerpf(seam_subsection[1], uv_seam_quads[i][0], uv_seam_quads[i][1], fac2);
+
+ Vec2Lerpf(seam_subsection[2], uv_seam_quads[i][3], uv_seam_quads[i][2], fac2);
+ Vec2Lerpf(seam_subsection[3], uv_seam_quads[i][3], uv_seam_quads[i][2], fac1);
+
+ /* if the bucket_clip_edges values Z values was kept we could avoid this
+ * Inset needs to be added so occlusiuon tests wont hit adjacent faces */
+ VecLerpf(edge_verts_inset_clip[0], edge_verts_inset[i][0], edge_verts_inset[i][1], fac1);
+ VecLerpf(edge_verts_inset_clip[1], edge_verts_inset[i][0], edge_verts_inset[i][1], fac2);
+
+ if (uv_image_rect(seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3], min_px, max_px, ibuf->x, ibuf->y, 1)) {
+ /* bounds between the seam rect and the uvspace bucket pixels */
+
+ for (y = min_px[1]; y < max_px[1]; y++) {
+ uv[1] = (((float)y)+0.5) / (float)ibuf->y; /* TODO - this is not pixel aligned correctly */
for (x = min_px[0]; x < max_px[0]; x++) {
- uv[0] = (((float)x)+0.5) / (float)ibuf->x;
-
- /* We need to find the closest point allong the face edge,
- * getting the screen_px_from_*** wont work because our actual location
- * is not relevent, since we are outside the face, Use VecLerpf to find
- * our location on the side of the face's UV */
- /*
- if (ps->projectIsOrtho) screen_px_from_ortho(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
- else screen_px_from_persp(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
- */
- /* Since this is a seam we need to work out where on the line this pixel is */
- fac = lambda_cp_line2(uv, uv_seam_quads[i][0], uv_seam_quads[i][1]);
- if (fac<0.0) {
- VECCOPY(pixelScreenCo, edge_verts[i][0]);
- } else if (fac>1.0) {
- VECCOPY(pixelScreenCo, edge_verts[i][1]);
- } else {
- VecLerpf(pixelScreenCo, edge_verts[i][0], edge_verts[i][1], fac);
- }
+ uv[0] = (((float)x)+0.5) / (float)ibuf->x;
- if (!ps->projectIsOrtho) {
- pixelScreenCo[3] = 1.0;
- Mat4MulVec4fl(ps->projectMat, pixelScreenCo);
- pixelScreenCo[0] = (float)(curarea->winx/2.0)+(curarea->winx/2.0)*pixelScreenCo[0]/pixelScreenCo[3];
- pixelScreenCo[1] = (float)(curarea->winy/2.0)+(curarea->winy/2.0)*pixelScreenCo[1]/pixelScreenCo[3];
- pixelScreenCo[2] = pixelScreenCo[2]/pixelScreenCo[3]; /* Use the depth for bucket point occlusion */
+ /* test we're inside uvspace bucket and triangle bounds */
+ if ( IsectPQ2Df(uv, seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3]) ) {
+
+ /* We need to find the closest point allong the face edge,
+ * getting the screen_px_from_*** wont work because our actual location
+ * is not relevent, since we are outside the face, Use VecLerpf to find
+ * our location on the side of the face's UV */
+ /*
+ if (ps->projectIsOrtho) screen_px_from_ortho(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
+ else screen_px_from_persp(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo);
+ */
+
+ /* Since this is a seam we need to work out where on the line this pixel is */
+ //fac = lambda_cp_line2(uv, uv_seam_quads[i][0], uv_seam_quads[i][1]);
+ fac = lambda_cp_line2(uv, seam_subsection[0], seam_subsection[1]);
+ if (fac<0.0) {
+ VECCOPY(pixelScreenCo, edge_verts_inset_clip[0]);
+ } else if (fac>1.0) {
+ VECCOPY(pixelScreenCo, edge_verts_inset_clip[1]);
+ } else {
+ VecLerpf(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac);
+ }
+
+ if (!ps->projectIsOrtho) {
+ pixelScreenCo[3] = 1.0;
+ Mat4MulVec4fl(ps->projectMat, pixelScreenCo);
+ pixelScreenCo[0] = (float)(curarea->winx/2.0)+(curarea->winx/2.0)*pixelScreenCo[0]/pixelScreenCo[3];
+ pixelScreenCo[1] = (float)(curarea->winy/2.0)+(curarea->winy/2.0)*pixelScreenCo[1]/pixelScreenCo[3];
+ pixelScreenCo[2] = pixelScreenCo[2]/pixelScreenCo[3]; /* Use the depth for bucket point occlusion */
+ }
+
+ project_paint_uvpixel_init(ps, ibuf, x, y, bucket_index, face_index, pixelScreenCo);
}
-
- project_paint_uvpixel_init(ps, ibuf, uv, x, y, face_index, pixelScreenCo);
}
}
}
}
}
}
-#endif
-#endif
+ return;
}
-
-
-
/* takes floating point screenspace min/max and returns int min/max to be used as indicies for ps->projectBuckets, ps->projectBucketFlags */
static void project_paint_rect(ProjectPaintState *ps, float min[2], float max[2], int bucket_min[2], int bucket_max[2])
{
@@ -1445,7 +1596,8 @@ static void project_bucket_bounds(ProjectPaintState *ps, int bucket_x, int bucke
bucket_bounds[ PROJ_BUCKET_TOP ] = ps->viewMin2D[1]+((bucket_y+1)*(ps->viewHeight / ps->bucketsY)); /* top */
}
-static void project_paint_bucket_init(ProjectPaintState *ps, int bucket_index)
+/* have bucket_bounds as an arg so we dont need to give bucket_x/y the rect function need */
+static void project_paint_bucket_init(ProjectPaintState *ps, int bucket_index, float bucket_bounds[4])
{
LinkNode *node;
int face_index;
@@ -1454,45 +1606,39 @@ static void project_paint_bucket_init(ProjectPaintState *ps, int bucket_index)
Image *tpage_last = NULL;
int tpage_index;
- /*printf("\tinit bucket %d\n", bucket_index);*/
-
- ps->projectBucketFlags[bucket_index] |= PROJ_BUCKET_INIT;
if ((node = ps->projectFaces[bucket_index])) {
do {
face_index = (int)node->link;
- /* Have we initialized this face in another bucket? */
- if ((ps->projectFaceFlags[face_index] & PROJ_FACE_INIT)==0) {
- ps->projectFaceFlags[face_index] |= PROJ_FACE_INIT;
+ /* Image context switching */
+ tf = ps->dm_mtface+face_index;
+ if (tpage_last != tf->tpage) {
+ tpage_last = tf->tpage;
- /* Image context switching */
- tf = ps->dm_mtface+face_index;
- if (tpage_last != tf->tpage) {
- tpage_last = tf->tpage;
-
- ps->imaContextIndex = -1; /* sanity check */
-
- for (tpage_index=0; tpage_index < ps->projectImageTotal; tpage_index++) {
- if (ps->projectImages[tpage_index] == tpage_last) {
- ps->imaContextIndex = tpage_index;
- break;
- }
- }
-
- if (ps->imaContextIndex==-1) {
- printf("Error, should never happen!\n");
- return;
+ ps->imaContextIndex = -1; /* sanity check */
+
+ for (tpage_index=0; tpage_index < ps->projectImageTotal; tpage_index++) {
+ if (ps->projectImages[tpage_index] == tpage_last) {
+ ps->imaContextIndex = tpage_index;
+ break;
}
-
- ibuf = BKE_image_get_ibuf(tpage_last, NULL); /* TODO - this may be slow */
}
- project_paint_face_init(ps, face_index, ibuf);
+ if (ps->imaContextIndex==-1) {
+ printf("Error, should never happen!\n");
+ return;
+ }
+
+ ibuf = BKE_image_get_ibuf(tpage_last, NULL); /* TODO - this may be slow */
}
+ project_paint_face_init(ps, bucket_index, face_index, bucket_bounds, ibuf);
+
node = node->next;
} while (node);
}
+
+ ps->projectBucketFlags[bucket_index] |= PROJ_BUCKET_INIT;
}
@@ -1606,6 +1752,13 @@ static void project_paint_delayed_face_init(ProjectPaintState *ps, MFace *mf, MT
}
}
}
+
+ if (ps->projectSeamBleed > 0.0) {
+ if (!mf->v4) {
+ ps->projectFaceSeamFlags[face_index] |= PROJ_FACE_NOSEAM4; /* so this wont show up as an untagged egde */
+ }
+ **ps->projectFaceSeamUVs[face_index] = MAXFLOAT; /* set as uninitialized */
+ }
}
static int BLI_linklist_index(struct LinkNode *list, void *ptr)
@@ -1645,7 +1798,8 @@ static void project_paint_begin( ProjectPaintState *ps, short mval[2])
/* memory sized to add to arena size */
int tot_bucketMem=0;
- int tot_faceFlagMem=0;
+ int tot_faceSeamFlagMem=0;
+ int tot_faceSeamUVMem=0;
int tot_faceListMem=0;
int tot_bucketFlagMem=0;
int tot_bucketVertFacesMem=0;
@@ -1676,35 +1830,45 @@ static void project_paint_begin( ProjectPaintState *ps, short mval[2])
tot_bucketMem = sizeof(LinkNode *) * ps->bucketsX * ps->bucketsY;
tot_faceListMem = sizeof(LinkNode *) * ps->bucketsX * ps->bucketsY;
- tot_faceFlagMem = sizeof(char) * ps->dm_totface;
+
tot_bucketFlagMem = sizeof(char) * ps->bucketsX * ps->bucketsY;
#ifndef PROJ_DEBUG_NOSEAMBLEED
- if (ps->projectSeamBleed > 0.0) /* UV Seams for bleeding */
+ if (ps->projectSeamBleed > 0.0) { /* UV Seams for bleeding */
tot_bucketVertFacesMem = sizeof(LinkNode *) * ps->dm_totvert;
+ tot_faceSeamFlagMem = sizeof(char) * ps->dm_totface;
+ tot_faceSeamUVMem = sizeof(float) * ps->dm_totface * 8;
+ }
#endif
ps->projectArena =
BLI_memarena_new( tot_bucketMem +
tot_faceListMem +
- tot_faceFlagMem +
+ tot_faceSeamFlagMem +
+ tot_faceSeamUVMem +
tot_bucketVertFacesMem + (1<<16));
ps->projectBuckets = (LinkNode **)BLI_memarena_alloc( ps->projectArena, tot_bucketMem);
ps->projectFaces= (LinkNode **)BLI_memarena_alloc( ps->projectArena, tot_faceListMem);
- ps->projectFaceFlags = (char *)BLI_memarena_alloc( ps->projectArena, tot_faceFlagMem);
+
ps->projectBucketFlags= (char *)BLI_memarena_alloc( ps->projectArena, tot_bucketFlagMem);
#ifndef PROJ_DEBUG_NOSEAMBLEED
- if (ps->projectSeamBleed > 0.0)
+ if (ps->projectSeamBleed > 0.0) {
ps->projectVertFaces= (LinkNode **)BLI_memarena_alloc( ps->projectArena, tot_bucketVertFacesMem);
+ ps->projectFaceSeamFlags = (char *)BLI_memarena_alloc( ps->projectArena, tot_faceSeamFlagMem);
+ ps->projectFaceSeamUVs= BLI_memarena_alloc( ps->projectArena, tot_faceSeamUVMem);
+ }
#endif
memset(ps->projectBuckets, 0, tot_bucketMem);
memset(ps->projectFaces, 0, tot_faceListMem);
- memset(ps->projectFaceFlags, 0, tot_faceFlagMem);
+ memset(ps->projectFaceSeamFlags,0, tot_faceSeamFlagMem);
memset(ps->projectBucketFlags, 0, tot_bucketFlagMem);
#ifndef PROJ_DEBUG_NOSEAMBLEED
- if (ps->projectSeamBleed > 0.0)
+ if (ps->projectSeamBleed > 0.0) {
memset(ps->projectVertFaces, 0, tot_bucketVertFacesMem);
+ /* TODO dosnt need zeroing? */
+ memset(ps->projectFaceSeamUVs, 0, tot_faceSeamUVMem);
+ }
#endif
Mat4Invert(ps->ob->imat, ps->ob->obmat);
@@ -2279,13 +2443,9 @@ static float Vec2Lenf_nosqrt_other(float *v1, float v2_1, float v2_2)
/* note, use a squared value so we can use Vec2Lenf_nosqrt
* be sure that you have done a bounds check first or this may fail */
-static int project_bucket_circle_isect(ProjectPaintState *ps, int bucket_x, int bucket_y, float cent[2], float radius_squared)
+/* only give bucket_bounds as an arg because we need it elsewhere */
+static int project_bucket_circle_isect(ProjectPaintState *ps, int bucket_x, int bucket_y, float cent[2], float radius_squared, float bucket_bounds[4])
{
- float bucket_bounds[4];
- //return 1;
-
- project_bucket_bounds(ps, bucket_x, bucket_y, bucket_bounds);
-
// printf("%d %d - %f %f %f %f - %f %f \n", bucket_x, bucket_y, bucket_bounds[0], bucket_bounds[1], bucket_bounds[2], bucket_bounds[3], cent[0], cent[1]);
/* first check if we are INSIDE the bucket */
@@ -2354,8 +2514,11 @@ static int imapaint_paint_sub_stroke_project(ProjectPaintState *ps, BrushPainter
int a;
short blend= ps->blend;
char *cp;
+
+ float bucket_bounds[4];
int bucket_x, bucket_y;
+
/* for smear only */
float mval_ofs[2];
float co[2];
@@ -2385,7 +2548,6 @@ static int imapaint_paint_sub_stroke_project(ProjectPaintState *ps, BrushPainter
smearArena = BLI_memarena_new(1<<16);
}
-
/* avoid a square root with every dist comparison */
brush_size_sqared = ps->brush->size * ps->brush->size;
@@ -2399,14 +2561,17 @@ static int imapaint_paint_sub_stroke_project(ProjectPaintState *ps, BrushPainter
for (bucket_y = bucket_min[1]; bucket_y < bucket_max[1]; bucket_y++) {
for (bucket_x = bucket_min[0]; bucket_x < bucket_max[0]; bucket_x++) {
- if (project_bucket_circle_isect(ps, bucket_x, bucket_y, mval_f, brush_size_sqared)) {
+ /* use bucket_bounds for project_bucket_circle_isect and project_paint_bucket_init*/
+ project_bucket_bounds(ps, bucket_x, bucket_y, bucket_bounds);
+
+ if (project_bucket_circle_isect(ps, bucket_x, bucket_y, mval_f, brush_size_sqared, bucket_bounds)) {
bucket_index = bucket_x + (bucket_y * ps->bucketsX);
/* Check this bucket and its faces are initialized */
if (ps->projectBucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
- /* This bucket may hold some uninitialized faces, initialize it */
- project_paint_bucket_init(ps, bucket_index);
+ /* No pixels initialized */
+ project_paint_bucket_init(ps, bucket_index, bucket_bounds);
}
/* TODO - we may want to init clone data in a seperate to project_paint_bucket_init