* Added buttons for accessing options "occlude", "backface cull" and "bleed", note that bleed is 0.0 by default, before it was always 2.0;
* use a faster method of getting a pixels screenspace location. * check if its possible to break out of pixel to bucket/face intersection early - ~7% overall speedup (ignoring redraw time). * removed scanline intersection function (added back incase they were needed but it looks like there not) * speedup for painting with only 1 image (use a loop without context switching checks) * more commenting + cleanup
This commit is contained in:
@@ -345,7 +345,9 @@ typedef struct TimeMarker {
|
||||
typedef struct ImagePaintSettings {
|
||||
struct Brush *brush;
|
||||
short flag, tool;
|
||||
int pad3;
|
||||
|
||||
/* for projection painting only - todo - use flags */
|
||||
float seam_bleed;
|
||||
} ImagePaintSettings;
|
||||
|
||||
typedef struct ParticleBrushData {
|
||||
@@ -799,6 +801,11 @@ typedef struct Scene {
|
||||
#define IMAGEPAINT_DRAW_TOOL 2
|
||||
#define IMAGEPAINT_DRAW_TOOL_DRAWING 4
|
||||
|
||||
/* projection painting only */
|
||||
#define IMAGEPAINT_PROJECT_XRAY 8
|
||||
#define IMAGEPAINT_PROJECT_BACKFACE 16
|
||||
#define IMAGEPAINT_PROJECT_IGNORE_SEAMS 32
|
||||
|
||||
/* toolsettings->uvcalc_flag */
|
||||
#define UVCALC_FILLHOLES 1
|
||||
#define UVCALC_NO_ASPECT_CORRECT 2 /* would call this UVCALC_ASPECT_CORRECT, except it should be default with old file */
|
||||
|
||||
@@ -6367,8 +6367,16 @@ static void editing_panel_mesh_paint(void)
|
||||
uiDefButBitS(block, TOG|BIT, BRUSH_AIRBRUSH, B_BRUSHCHANGE, "Airbrush", xco+10,yco-50,butw,19, &brush->flag, 0, 0, 0, 0, "Keep applying paint effect while holding mouse (spray)");
|
||||
uiDefButF(block, NUM, B_NOP, "Rate ", xco+10,yco-70,butw,19, &brush->rate, 0.01, 1.0, 0, 0, "Number of paints per second for Airbrush");
|
||||
uiBlockEndAlign(block);
|
||||
|
||||
|
||||
yco -= 25;
|
||||
|
||||
/* Projection Painting */
|
||||
uiBlockBeginAlign(block);
|
||||
uiDefButBitS(block, TOGN|BIT, IMAGEPAINT_PROJECT_XRAY, B_NOP, "Occlude", xco+10,yco-70,butw,19, &settings->imapaint.flag, 0, 0, 0, 0, "Only paint onto the faces directly under the brush (slower)");
|
||||
uiDefButBitS(block, TOGN|BIT, IMAGEPAINT_PROJECT_BACKFACE, B_NOP, "Backface Cull", xco+10,yco-90,butw,19, &settings->imapaint.flag, 0, 0, 0, 0, "Ignore faces pointing away from the view (faster)");
|
||||
uiDefButBitS(block, TOGN|BIT, IMAGEPAINT_PROJECT_IGNORE_SEAMS, B_NOP, "Bleed", xco+10,yco-110,butw/2,19, &settings->imapaint.flag, 0, 0, 0, 0, "Extend paint beyond the faces UVs to reduce seams (in pixels, slower)");
|
||||
uiDefButF(block, NUM, B_NOP, "", xco+10 + (butw/2),yco-110,butw/2,19, &settings->imapaint.seam_bleed, 2.0, 8.0, 0, 0, "Extend paint beyond the faces UVs to reduce seams (in pixels, slower)");
|
||||
uiBlockEndAlign(block);
|
||||
|
||||
uiBlockBeginAlign(block);
|
||||
uiDefButF(block, COL, B_VPCOLSLI, "", 0,yco,200,19, brush->rgb, 0, 0, 0, 0, "");
|
||||
|
||||
@@ -139,7 +139,8 @@ typedef struct ImagePaintPartialRedraw {
|
||||
int enabled;
|
||||
} ImagePaintPartialRedraw;
|
||||
|
||||
/* testing options */
|
||||
|
||||
/* ProjectionPaint defines */
|
||||
|
||||
/* approx the number of buckets to have under the brush,
|
||||
* used with the brush size to set the ps->buckets_x and ps->buckets_y value.
|
||||
@@ -152,12 +153,10 @@ typedef struct ImagePaintPartialRedraw {
|
||||
#define PROJ_BUCKET_RECT_MIN 4
|
||||
#define PROJ_BUCKET_RECT_MAX 256
|
||||
|
||||
|
||||
#define PROJ_BOUNDBOX_DIV 6 /* TODO - test other values, this is a guess, seems ok */
|
||||
#define PROJ_BOUNDBOX_DIV 8
|
||||
#define PROJ_BOUNDBOX_SQUARED (PROJ_BOUNDBOX_DIV * PROJ_BOUNDBOX_DIV)
|
||||
|
||||
//#define PROJ_DEBUG_PAINT 1
|
||||
#define PROJ_DEBUG_NOSCANLINE 1
|
||||
//#define PROJ_DEBUG_NOSEAMBLEED 1
|
||||
//#define PROJ_DEBUG_PRINT_THREADS 1
|
||||
#define PROJ_DEBUG_WINCLIP 1
|
||||
@@ -185,6 +184,9 @@ typedef struct ImagePaintPartialRedraw {
|
||||
#define PROJ_BUCKET_BOTTOM 2
|
||||
#define PROJ_BUCKET_TOP 3
|
||||
|
||||
/* This is mainly a convenience struct used so we can keep an array of images we use
|
||||
* Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread
|
||||
* because 'partRedrawRect' and 'touch' values would not be thread safe */
|
||||
typedef struct ProjectPaintImage {
|
||||
Image *ima;
|
||||
ImBuf *ibuf;
|
||||
@@ -193,6 +195,7 @@ typedef struct ProjectPaintImage {
|
||||
int touch;
|
||||
} ProjectPaintImage;
|
||||
|
||||
/* Main projection painting struct passed to all projection painting functions */
|
||||
typedef struct ProjectPaintState {
|
||||
Brush *brush;
|
||||
short tool, blend;
|
||||
@@ -254,13 +257,6 @@ typedef struct ProjectPaintState {
|
||||
int context_bucket_x, context_bucket_y; /* must lock threads while accessing these */
|
||||
} ProjectPaintState;
|
||||
|
||||
#ifndef PROJ_DEBUG_NOSCANLINE
|
||||
typedef struct ProjectScanline {
|
||||
int v[3]; /* verts for this scanline, 0,1,2 or 0,2,3 */
|
||||
float x_limits[2]; /* UV min|max for this scanline */
|
||||
} ProjectScanline;
|
||||
#endif
|
||||
|
||||
typedef struct ProjectPixel {
|
||||
float projCo2D[2]; /* the floating point screen projection of this pixel */
|
||||
char origColor[4];
|
||||
@@ -461,7 +457,7 @@ static void undo_imagepaint_push_end()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* fast projection bucket array lookup, use the safe version for bound checking */
|
||||
static int project_paint_BucketOffset(ProjectPaintState *ps, float projCo2D[2])
|
||||
{
|
||||
/* If we were not dealing with screenspace 2D coords we could simple do...
|
||||
@@ -567,8 +563,7 @@ static float tri_depth_2d(float v1[3], float v2[3], float v3[3], float pt[2], fl
|
||||
}
|
||||
|
||||
|
||||
/* return the topmost face in screen coords index or -1
|
||||
* bucket_index can be -1 if we dont know it to begin with */
|
||||
/* Return the top-most face index that the screen space coord 'pt' touches (or -1) */
|
||||
static int project_paint_PickFace(ProjectPaintState *ps, float pt[2], float w[3], int *side) {
|
||||
LinkNode *node;
|
||||
float w_tmp[3];
|
||||
@@ -626,6 +621,8 @@ static int project_paint_PickFace(ProjectPaintState *ps, float pt[2], float w[3]
|
||||
return best_face_index; /* will be -1 or a valid face */
|
||||
}
|
||||
|
||||
/* TODO move to "source/blender/imbuf/intern/imageprocess.c" - also try bilinear weight which is faster */
|
||||
|
||||
/**************************************************************************
|
||||
* INTERPOLATIONS
|
||||
*
|
||||
@@ -714,8 +711,7 @@ static void bicubic_interpolation_px(ImBuf *in, float x, float y, float rgba_fp[
|
||||
}
|
||||
}
|
||||
|
||||
/* bucket_index is optional, since in some cases we know it */
|
||||
/* TODO FLOAT */ /* add a function that does this for float buffers */
|
||||
/* Set the top-most face color that the screen space coord 'pt' touches (or return 0 if none touch) */
|
||||
static int project_paint_PickColor(ProjectPaintState *ps, float pt[2], float *rgba_fp, char *rgba, int interp)
|
||||
{
|
||||
float w[3], uv[2];
|
||||
@@ -806,10 +802,11 @@ static int project_paint_PickColor(ProjectPaintState *ps, float pt[2], float *rg
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* return...
|
||||
* 0 : no occlusion
|
||||
/* Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusuion test)
|
||||
* return...
|
||||
* 0 : no occlusion
|
||||
* -1 : no occlusion but 2D intersection is true (avoid testing the other half of a quad)
|
||||
* 1 : occluded */
|
||||
* 1 : occluded */
|
||||
|
||||
static int project_paint_PointOcclude(float pt[3], float v1[3], float v2[3], float v3[3])
|
||||
{
|
||||
@@ -837,7 +834,9 @@ static int project_paint_PointOcclude(float pt[3], float v1[3], float v2[3], flo
|
||||
}
|
||||
|
||||
|
||||
/* check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be used for comparison */
|
||||
/* Check if a screenspace location is occluded by any other faces
|
||||
* check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be used for comparison
|
||||
* and dosn't need to be correct in relation to X and Y coords (this is the case in perspective view) */
|
||||
static int project_bucket_point_occluded(ProjectPaintState *ps, int bucket_index, int orig_face, float pixelScreenCo[4])
|
||||
{
|
||||
LinkNode *node = ps->bucketFaces[bucket_index];
|
||||
@@ -871,23 +870,8 @@ 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
|
||||
* the next ~5 to ~200 runs will can hit the first face each time. */
|
||||
if (ps->bucketFaces[bucket_index] != node) {
|
||||
/* SWAP(void *, ps->bucketFaces[bucket_index]->link, node->link); */
|
||||
|
||||
/* dont need to use swap since we alredy have face_index */
|
||||
node->link = ps->bucketFaces[bucket_index]->link; /* move the value item to the current value */
|
||||
ps->bucketFaces[bucket_index]->link = (void *) face_index;
|
||||
|
||||
/*printf("swapping %d %d\n", (int)node->link, face_index);*/
|
||||
} /*else {
|
||||
printf("first hit %d\n", face_index);
|
||||
}*/
|
||||
#endif
|
||||
/* TODO - we may want to cache the first hit,
|
||||
* it is not possible to swap the face order in the list anymore */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -946,111 +930,16 @@ static int line_isect_x(float p1[2], float p2[2], float x_level, float *y_isect)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PROJ_DEBUG_NOSCANLINE
|
||||
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 */
|
||||
int totscanlines = 0;
|
||||
short i1=0,i2=0,i3=0;
|
||||
|
||||
if (v4) { /* This is a quad?*/
|
||||
int i4=0, i_mid=0;
|
||||
float xi1, xi2, xi3, xi4, xi_mid;
|
||||
|
||||
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 = 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;
|
||||
sc->v[1] = 1;
|
||||
sc->v[2] = 2;
|
||||
sc->x_limits[0] = MIN2(xi1, xi2);
|
||||
sc->x_limits[1] = MAX2(xi1, xi2);
|
||||
totscanlines = 1;
|
||||
} else {
|
||||
if (i2 != ISECT_TRUE_P2)
|
||||
i3 = line_isect_y(v3, v4, y_level, &xi3);
|
||||
if (i1 != ISECT_TRUE_P1 && i3 != ISECT_TRUE_P2)
|
||||
i4 = line_isect_y(v4, v1, y_level, &xi4);
|
||||
|
||||
if (i3 && i4) { /* second 2 edges only intersect, same as above */
|
||||
sc->v[0] = 0;
|
||||
sc->v[1] = 2;
|
||||
sc->v[2] = 3;
|
||||
sc->x_limits[0] = MIN2(xi3, xi4);
|
||||
sc->x_limits[1] = MAX2(xi3, xi4);
|
||||
totscanlines = 1;
|
||||
} else {
|
||||
/* 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 = 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;
|
||||
sc->v[2] = 2;
|
||||
sc->x_limits[0] = MIN2((i1?xi1:xi2), xi_mid);
|
||||
sc->x_limits[1] = MAX2((i1?xi1:xi2), xi_mid);
|
||||
|
||||
sc++;
|
||||
sc->v[0] = 0;
|
||||
sc->v[1] = 2;
|
||||
sc->v[2] = 3;
|
||||
sc->x_limits[0] = MIN2((i3?xi3:xi4), xi_mid);
|
||||
sc->x_limits[1PROJ_DEBUG_NOSEAMBLEED] = MAX2((i3?xi3:xi4), xi_mid);
|
||||
|
||||
totscanlines = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { /* triangle */
|
||||
int i = 0;
|
||||
|
||||
i1 = line_isect_y(v1, v2, y_level, &sc->x_limits[0]);
|
||||
if (i1) i++;
|
||||
|
||||
if (i1 != ISECT_TRUE_P2) {
|
||||
i2 = line_isect_y(v2, v3, y_level, &sc->x_limits[i]);
|
||||
if (i2) i++;
|
||||
}
|
||||
|
||||
/* if the triangle intersects then the first 2 lines must */
|
||||
if (i!=0) {
|
||||
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 = line_isect_y(v3, v1, y_level, &sc->x_limits[i]);
|
||||
if (i3) i++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (i==2) {
|
||||
if (sc->x_limits[0] > sc->x_limits[1]) {
|
||||
SWAP(float, sc->x_limits[0], sc->x_limits[1]);
|
||||
}
|
||||
sc->v[0] = 0;
|
||||
sc->v[1] = 1;
|
||||
sc->v[2] = 2;
|
||||
totscanlines = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* done setting up scanlines */
|
||||
return totscanlines;
|
||||
}
|
||||
#endif // PROJ_DEBUG_NOSCANLINE
|
||||
|
||||
/* simple func use for comparing UV locations to check if there are seams */
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* return zero if there is no area in the returned rectangle */
|
||||
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)
|
||||
/* set min_px and max_px to the image space bounds of the UV coords
|
||||
* return zero if there is no area in the returned rectangle */
|
||||
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 ibuf_x, int ibuf_y, int is_quad)
|
||||
{
|
||||
float min_uv[2], max_uv[2]; /* UV bounds */
|
||||
|
||||
@@ -1062,11 +951,11 @@ static int uv_image_rect(float uv1[2], float uv2[2], float uv3[2], float uv4[2],
|
||||
if (is_quad)
|
||||
DO_MINMAX2(uv4, min_uv, max_uv);
|
||||
|
||||
min_px[0] = (int)(x_px * min_uv[0]);
|
||||
min_px[1] = (int)(y_px * min_uv[1]);
|
||||
min_px[0] = (int)(ibuf_x * min_uv[0]);
|
||||
min_px[1] = (int)(ibuf_y * min_uv[1]);
|
||||
|
||||
max_px[0] = (int)(x_px * max_uv[0]) +1;
|
||||
max_px[1] = (int)(y_px * max_uv[1]) +1;
|
||||
max_px[0] = (int)(ibuf_x * max_uv[0]) +1;
|
||||
max_px[1] = (int)(ibuf_y * max_uv[1]) +1;
|
||||
|
||||
/*printf("%d %d %d %d \n", min_px[0], min_px[1], max_px[0], max_px[1]);*/
|
||||
|
||||
@@ -1075,7 +964,9 @@ static int uv_image_rect(float uv1[2], float uv2[2], float uv3[2], float uv4[2],
|
||||
}
|
||||
|
||||
#ifndef PROJ_DEBUG_NOSEAMBLEED
|
||||
/* TODO - set the seam flag on the other face to avoid double lookups */
|
||||
|
||||
/* This function returns 1 if this face has a seam along the 2 face-vert indicies
|
||||
* 'orig_i1_fidx' and 'orig_i2_fidx' */
|
||||
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;
|
||||
@@ -1111,9 +1002,6 @@ 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;
|
||||
|
||||
/* set up the other face */
|
||||
@@ -1140,12 +1028,13 @@ static int check_seam(ProjectPaintState *ps, int orig_face, int orig_i1_fidx, in
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* TODO - move to arithb.c */
|
||||
/* Converts an angle to a length that can be used for maintaining an even margin around UV's */
|
||||
static float angleToLength(float angle)
|
||||
{
|
||||
float x,y, fac;
|
||||
|
||||
// Alredy accounted for
|
||||
// already accounted for
|
||||
if (angle < 0.000001)
|
||||
return 1.0;
|
||||
|
||||
@@ -1162,8 +1051,10 @@ static float angleToLength(float angle)
|
||||
return sqrt((x*x)+(y*y));
|
||||
}
|
||||
|
||||
/* takes a faces UV's and assigns outset coords to outset_uv */
|
||||
static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], float scaler, int x_px, int y_px, int is_quad)
|
||||
/* Calculate outset UV's, this is not the same as simply scaling the UVs,
|
||||
* since the outset coords are a margin that keep an even distance from the original UV's,
|
||||
* note that the image aspect is taken into account */
|
||||
static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], float scaler, int ima_x, int ima_y, int is_quad)
|
||||
{
|
||||
float a1,a2,a3,a4=0.0;
|
||||
float puv[4][2]; /* pixelspace uv's */
|
||||
@@ -1171,18 +1062,18 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], float sc
|
||||
float dir1[2], dir2[2], dir3[2], dir4[2];
|
||||
|
||||
/* make UV's in pixel space so we can */
|
||||
puv[0][0] = orig_uv[0][0] * x_px;
|
||||
puv[0][1] = orig_uv[0][1] * y_px;
|
||||
puv[0][0] = orig_uv[0][0] * ima_x;
|
||||
puv[0][1] = orig_uv[0][1] * ima_y;
|
||||
|
||||
puv[1][0] = orig_uv[1][0] * x_px;
|
||||
puv[1][1] = orig_uv[1][1] * y_px;
|
||||
puv[1][0] = orig_uv[1][0] * ima_x;
|
||||
puv[1][1] = orig_uv[1][1] * ima_y;
|
||||
|
||||
puv[2][0] = orig_uv[2][0] * x_px;
|
||||
puv[2][1] = orig_uv[2][1] * y_px;
|
||||
puv[2][0] = orig_uv[2][0] * ima_x;
|
||||
puv[2][1] = orig_uv[2][1] * ima_y;
|
||||
|
||||
if (is_quad) {
|
||||
puv[3][0] = orig_uv[3][0] * x_px;
|
||||
puv[3][1] = orig_uv[3][1] * y_px;
|
||||
puv[3][0] = orig_uv[3][0] * ima_x;
|
||||
puv[3][1] = orig_uv[3][1] * ima_y;
|
||||
}
|
||||
|
||||
/* face edge directions */
|
||||
@@ -1202,22 +1093,16 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], float sc
|
||||
}
|
||||
|
||||
if (is_quad) {
|
||||
a1 = NormalizedVecAngle2_2D(dir4, dir1);
|
||||
a2 = NormalizedVecAngle2_2D(dir1, dir2);
|
||||
a3 = NormalizedVecAngle2_2D(dir2, dir3);
|
||||
a4 = NormalizedVecAngle2_2D(dir3, dir4);
|
||||
a1 = angleToLength( NormalizedVecAngle2_2D(dir4, dir1) );
|
||||
a2 = angleToLength( NormalizedVecAngle2_2D(dir1, dir2) );
|
||||
a3 = angleToLength( NormalizedVecAngle2_2D(dir2, dir3) );
|
||||
a4 = angleToLength( NormalizedVecAngle2_2D(dir3, dir4) );
|
||||
} else {
|
||||
a1 = NormalizedVecAngle2_2D(dir3, dir1);
|
||||
a2 = NormalizedVecAngle2_2D(dir1, dir2);
|
||||
a3 = NormalizedVecAngle2_2D(dir2, dir3);
|
||||
a1 = angleToLength( NormalizedVecAngle2_2D(dir3, dir1) );
|
||||
a2 = angleToLength( NormalizedVecAngle2_2D(dir1, dir2) );
|
||||
a3 = angleToLength( NormalizedVecAngle2_2D(dir2, dir3) );
|
||||
}
|
||||
|
||||
a1 = angleToLength(a1);
|
||||
a2 = angleToLength(a2);
|
||||
a3 = angleToLength(a3);
|
||||
if (is_quad)
|
||||
a4 = angleToLength(a4);
|
||||
|
||||
if (is_quad) {
|
||||
Vec2Subf(no1, dir4, dir1);
|
||||
Vec2Subf(no2, dir1, dir2);
|
||||
@@ -1235,17 +1120,17 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], float sc
|
||||
Vec2Addf(outset_uv[1], puv[1], no2);
|
||||
Vec2Addf(outset_uv[2], puv[2], no3);
|
||||
Vec2Addf(outset_uv[3], puv[3], no4);
|
||||
outset_uv[0][0] /= x_px;
|
||||
outset_uv[0][1] /= y_px;
|
||||
outset_uv[0][0] /= ima_x;
|
||||
outset_uv[0][1] /= ima_y;
|
||||
|
||||
outset_uv[1][0] /= x_px;
|
||||
outset_uv[1][1] /= y_px;
|
||||
outset_uv[1][0] /= ima_x;
|
||||
outset_uv[1][1] /= ima_y;
|
||||
|
||||
outset_uv[2][0] /= x_px;
|
||||
outset_uv[2][1] /= y_px;
|
||||
outset_uv[2][0] /= ima_x;
|
||||
outset_uv[2][1] /= ima_y;
|
||||
|
||||
outset_uv[3][0] /= x_px;
|
||||
outset_uv[3][1] /= y_px;
|
||||
outset_uv[3][0] /= ima_x;
|
||||
outset_uv[3][1] /= ima_y;
|
||||
} else {
|
||||
Vec2Subf(no1, dir3, dir1);
|
||||
Vec2Subf(no2, dir1, dir2);
|
||||
@@ -1259,14 +1144,14 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], float sc
|
||||
Vec2Addf(outset_uv[0], puv[0], no1);
|
||||
Vec2Addf(outset_uv[1], puv[1], no2);
|
||||
Vec2Addf(outset_uv[2], puv[2], no3);
|
||||
outset_uv[0][0] /= x_px;
|
||||
outset_uv[0][1] /= y_px;
|
||||
outset_uv[0][0] /= ima_x;
|
||||
outset_uv[0][1] /= ima_y;
|
||||
|
||||
outset_uv[1][0] /= x_px;
|
||||
outset_uv[1][1] /= y_px;
|
||||
outset_uv[1][0] /= ima_x;
|
||||
outset_uv[1][1] /= ima_y;
|
||||
|
||||
outset_uv[2][0] /= x_px;
|
||||
outset_uv[2][1] /= y_px;
|
||||
outset_uv[2][0] /= ima_x;
|
||||
outset_uv[2][1] /= ima_y;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1315,6 +1200,10 @@ static float lambda_cp_line2(float p[2], float l1[2], float l2[2])
|
||||
return(Inp2f(u,h)/Inp2f(u,u));
|
||||
}
|
||||
|
||||
/* Converts a UV location to a 3D screenspace location
|
||||
* Takes a 'uv' and 3 UV coords, and sets the values of pixelScreenCo
|
||||
*
|
||||
* This is used for finding a pixels location in screenspace for painting */
|
||||
static void screen_px_from_ortho(
|
||||
ProjectPaintState *ps, float uv[2],
|
||||
float v1co[3], float v2co[3], float v3co[3], /* Screenspace coords */
|
||||
@@ -1328,32 +1217,40 @@ static void screen_px_from_ortho(
|
||||
pixelScreenCo[2] = v1co[2]*w[0] + v2co[2]*w[1] + v3co[2]*w[2];
|
||||
}
|
||||
|
||||
/* same as screen_px_from_ortho except we need to take into account
|
||||
* the perspective W coord for each vert */
|
||||
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 w[3];
|
||||
float w[3], wtot;
|
||||
BarycentricWeightsSimple2f(uv1co,uv2co,uv3co,uv,w);
|
||||
|
||||
/* re-weight from the 4th coord of each screen vert */
|
||||
w[0] *= v1co[3];
|
||||
w[1] *= v2co[3];
|
||||
w[2] *= v3co[3];
|
||||
|
||||
wtot = w[0]+w[1]+w[2];
|
||||
|
||||
w[0]/=wtot;
|
||||
w[1]/=wtot;
|
||||
w[2]/=wtot;
|
||||
/* done re-weighting */
|
||||
|
||||
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);
|
||||
|
||||
// if( pixelScreenCo[3] > 0.001 ) { ??? TODO
|
||||
/* screen space, not clamped */
|
||||
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 */
|
||||
pixelScreenCo[2] = v1co[2]*w[0] + v2co[2]*w[1] + v3co[2]*w[2];
|
||||
}
|
||||
|
||||
|
||||
/* Only run this function once for new ProjectPixelClone's */
|
||||
#define pixel_size 4
|
||||
#define IMA_CHAR_PX_SIZE 4
|
||||
|
||||
/* 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])
|
||||
{
|
||||
ProjectPixel *projPixel;
|
||||
@@ -1394,13 +1291,14 @@ static void project_paint_uvpixel_init(ProjectPaintState *ps, int thread_index,
|
||||
projPixel = (ProjectPixel *)BLI_memarena_alloc(ps->arena_mt[thread_index], size);
|
||||
|
||||
if (ibuf->rect_float) {
|
||||
projPixel->pixel = (void *) ((( float * ) ibuf->rect_float) + (( x + y * ibuf->x ) * pixel_size));
|
||||
projPixel->pixel = (void *) ((( float * ) ibuf->rect_float) + (( x + y * ibuf->x ) * IMA_CHAR_PX_SIZE));
|
||||
/* TODO float support for origColor */
|
||||
} else {
|
||||
projPixel->pixel = (void *) ((( char * ) ibuf->rect) + (( x + y * ibuf->x ) * pixel_size));
|
||||
projPixel->pixel = (void *) ((( char * ) ibuf->rect) + (( x + y * ibuf->x ) * IMA_CHAR_PX_SIZE));
|
||||
*((unsigned int *)projPixel->origColor) = *((unsigned int *)projPixel->pixel);
|
||||
}
|
||||
|
||||
/* screenspace unclamped, we could keep its z and w values but dont need them at the moment */
|
||||
VECCOPY2D(projPixel->projCo2D, pixelScreenCo);
|
||||
|
||||
projPixel->x_px = x;
|
||||
@@ -1430,8 +1328,6 @@ static void project_paint_uvpixel_init(ProjectPaintState *ps, int thread_index,
|
||||
}
|
||||
}
|
||||
|
||||
/* screenspace unclamped */
|
||||
|
||||
#ifdef PROJ_DEBUG_PAINT
|
||||
if (ibuf->rect_float) ((float *)projPixel->pixel)[1] = 0;
|
||||
else ((char *)projPixel->pixel)[1] = 0;
|
||||
@@ -1446,6 +1342,7 @@ static void project_paint_uvpixel_init(ProjectPaintState *ps, int thread_index,
|
||||
}
|
||||
}
|
||||
|
||||
/* intersect two 2D boundboxes */
|
||||
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]);
|
||||
@@ -1626,7 +1523,8 @@ static void rect_to_uvspace(
|
||||
}
|
||||
|
||||
|
||||
/* initialize pixels from this face where it intersects with the bucket_index, initialize pixels for removing seams */
|
||||
/* One of the most important function for projectiopn painting, since it selects the pixels to be added into each bucket.
|
||||
* initialize pixels from this face where it intersects with the bucket_index, optionally initialize pixels for removing seams */
|
||||
static void project_paint_face_init(ProjectPaintState *ps, int thread_index, int bucket_index, int face_index, int image_index, float bucket_bounds[4], ImBuf *ibuf)
|
||||
{
|
||||
/* Projection vars, to get the 3D locations into screen space */
|
||||
@@ -1657,21 +1555,19 @@ static void project_paint_face_init(ProjectPaintState *ps, int thread_index, int
|
||||
float xhalfpx, yhalfpx;
|
||||
float ibuf_xf = ibuf->x, ibuf_yf = ibuf->y;
|
||||
|
||||
int i1,i2,i3;
|
||||
int has_x_isect = -1, has_isect = -1; /* for early loop exit */
|
||||
|
||||
/* 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
|
||||
|
||||
int i1,i2,i3;
|
||||
|
||||
vCo[0] = ps->dm_mvert[ (*(&mf->v1 )) ].co;
|
||||
vCo[1] = ps->dm_mvert[ (*(&mf->v1 + 1)) ].co;
|
||||
vCo[2] = ps->dm_mvert[ (*(&mf->v1 + 2)) ].co;
|
||||
|
||||
|
||||
|
||||
/* Use tf_uv_pxoffset instead of tf->uv so we can offset the UV half a pixel
|
||||
* this is done so we can avoid offseting all the pixels by 0.5 which causes
|
||||
* problems when wrapping negative coords */
|
||||
xhalfpx = 0.5 / ibuf_xf;
|
||||
yhalfpx = 0.5 / ibuf_yf;
|
||||
|
||||
@@ -1720,11 +1616,13 @@ static void project_paint_face_init(ProjectPaintState *ps, int thread_index, int
|
||||
uvpixel_rect_intersect(min_px, max_px, min_px_bucket, max_px_bucket, min_px_tf, max_px_tf);
|
||||
|
||||
/* clip face and */
|
||||
|
||||
|
||||
|
||||
has_isect = 0;
|
||||
for (y = min_px[1]; y < max_px[1]; y++) {
|
||||
//uv[1] = (((float)y) + 0.5) / (float)ibuf->y;
|
||||
uv[1] = (float)y / ibuf_yf; /* use pixel offset UV coords instead */
|
||||
|
||||
has_x_isect = 0;
|
||||
for (x = min_px[0]; x < max_px[0]; x++) {
|
||||
//uv[0] = (((float)x) + 0.5) / ibuf->x;
|
||||
uv[0] = (float)x / ibuf_xf; /* use pixel offset UV coords instead */
|
||||
@@ -1736,12 +1634,22 @@ static void project_paint_face_init(ProjectPaintState *ps, int thread_index, int
|
||||
if (ps->is_ortho) {
|
||||
screen_px_from_ortho(ps, uv, v1coSS,v2coSS,v3coSS, uv1co,uv2co,uv3co, pixelScreenCo);
|
||||
} else {
|
||||
screen_px_from_persp(ps, uv, vCo[i1],vCo[i2],vCo[i3], uv1co,uv2co,uv3co, pixelScreenCo);
|
||||
screen_px_from_persp(ps, uv, v1coSS,v2coSS,v3coSS, uv1co,uv2co,uv3co, pixelScreenCo);
|
||||
}
|
||||
|
||||
project_paint_uvpixel_init(ps, thread_index, ibuf, x, y, bucket_index, face_index, image_index, pixelScreenCo);
|
||||
|
||||
has_x_isect = has_isect = 1;
|
||||
} else if (has_x_isect) {
|
||||
/* assuming the face is not a bow-tie - we know we cant intersect again on the X */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* no intersection for this entire row, after some intersection above means we can quit now */
|
||||
if (has_x_isect==0 && has_isect) {
|
||||
//break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(i--);
|
||||
@@ -1845,10 +1753,13 @@ static void project_paint_face_init(ProjectPaintState *ps, int thread_index, int
|
||||
|
||||
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 */
|
||||
|
||||
|
||||
has_isect = 0;
|
||||
for (y = min_px[1]; y < max_px[1]; y++) {
|
||||
// uv[1] = (((float)y) + 0.5) / (float)ibuf->y;
|
||||
uv[1] = (float)y / ibuf_yf; /* use offset uvs instead */
|
||||
|
||||
has_x_isect = 0;
|
||||
for (x = min_px[0]; x < max_px[0]; x++) {
|
||||
//uv[0] = (((float)x) + 0.5) / (float)ibuf->x;
|
||||
uv[0] = (float)x / ibuf_xf; /* use offset uvs instead */
|
||||
@@ -1882,8 +1793,16 @@ static void project_paint_face_init(ProjectPaintState *ps, int thread_index, int
|
||||
}
|
||||
|
||||
project_paint_uvpixel_init(ps, thread_index, ibuf, x, y, bucket_index, face_index, image_index, pixelScreenCo);
|
||||
} else if (has_x_isect) {
|
||||
/* assuming the face is not a bow-tie - we know we cant intersect again on the X */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* no intersection for this entire row, after some intersection above means we can quit now */
|
||||
if (has_x_isect==0 && has_isect) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1913,6 +1832,7 @@ static void project_paint_rect(ProjectPaintState *ps, float min[2], float max[2]
|
||||
CLAMP(bucket_max[1], 0, ps->buckets_y);
|
||||
}
|
||||
|
||||
/* set bucket_bounds to a screen space-aligned floating point bound-box */
|
||||
static void project_bucket_bounds(ProjectPaintState *ps, int bucket_x, int bucket_y, float bucket_bounds[4])
|
||||
{
|
||||
bucket_bounds[ PROJ_BUCKET_LEFT ] = ps->screen_min[0]+((bucket_x)*(ps->screen_width / ps->buckets_x)); /* left */
|
||||
@@ -1922,57 +1842,65 @@ static void project_bucket_bounds(ProjectPaintState *ps, int bucket_x, int bucke
|
||||
bucket_bounds[ PROJ_BUCKET_TOP ] = ps->screen_min[1]+((bucket_y+1)*(ps->screen_height / ps->buckets_y)); /* top */
|
||||
}
|
||||
|
||||
/* have bucket_bounds as an arg so we dont need to give bucket_x/y the rect function need */
|
||||
/* Fill this bucket with pixels from the faces that intersect it.
|
||||
*
|
||||
* have bucket_bounds as an argument so we don;t need to give bucket_x/y the rect function needs */
|
||||
static void project_paint_bucket_init(ProjectPaintState *ps, int thread_index, int bucket_index, float bucket_bounds[4])
|
||||
{
|
||||
LinkNode *node;
|
||||
int face_index, image_index;
|
||||
ImBuf *ibuf;
|
||||
ImBuf *ibuf = NULL;
|
||||
MTFace *tf;
|
||||
|
||||
Image *tpage_last = NULL;
|
||||
int tpage_index;
|
||||
|
||||
if ((node = ps->bucketFaces[bucket_index])) {
|
||||
do {
|
||||
face_index = (int)node->link;
|
||||
|
||||
/* Image context switching */
|
||||
tf = ps->dm_mtface+face_index;
|
||||
if (tpage_last != tf->tpage) {
|
||||
tpage_last = tf->tpage;
|
||||
|
||||
image_index = -1; /* sanity check */
|
||||
|
||||
for (tpage_index=0; tpage_index < ps->image_tot; tpage_index++) {
|
||||
if (ps->projImages[tpage_index].ima == tpage_last) {
|
||||
image_index = tpage_index;
|
||||
break;
|
||||
|
||||
if (ps->image_tot==1) {
|
||||
/* Simple loop, no context switching */
|
||||
ibuf = ps->projImages[0].ibuf;
|
||||
do {
|
||||
project_paint_face_init(ps, thread_index, bucket_index, (int)node->link, 0, bucket_bounds, ibuf);
|
||||
node = node->next;
|
||||
} while (node);
|
||||
} else {
|
||||
|
||||
/* More complicated loop, switch between images */
|
||||
do {
|
||||
face_index = (int)node->link;
|
||||
|
||||
/* Image context switching */
|
||||
tf = ps->dm_mtface+face_index;
|
||||
if (tpage_last != tf->tpage) {
|
||||
tpage_last = tf->tpage;
|
||||
|
||||
image_index = -1; /* sanity check */
|
||||
|
||||
for (image_index=0; image_index < ps->image_tot; image_index++) {
|
||||
if (ps->projImages[image_index].ima == tpage_last) {
|
||||
ibuf = ps->projImages[image_index].ibuf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* context switching done */
|
||||
|
||||
if (image_index==-1) {
|
||||
printf("Error, should never happen!\n");
|
||||
return;
|
||||
}
|
||||
project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf);
|
||||
|
||||
ibuf = ps->projImages[image_index].ibuf;
|
||||
}
|
||||
project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf);
|
||||
|
||||
node = node->next;
|
||||
} while (node);
|
||||
node = node->next;
|
||||
} while (node);
|
||||
}
|
||||
}
|
||||
|
||||
ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT;
|
||||
}
|
||||
|
||||
|
||||
/* We want to know if a bucket and a face overlap in screenspace
|
||||
/* We want to know if a bucket and a face overlap in screen-space
|
||||
*
|
||||
* Note, if this ever returns false positives its not that bad, since a face in the bounding area will have its pixels
|
||||
* calculated when it might not be needed later, (at the moment at least)
|
||||
* obviously it shouldnt have bugs though */
|
||||
* obviously it shouldn't have bugs though */
|
||||
|
||||
static int project_bucket_face_isect(ProjectPaintState *ps, float min[2], float max[2], int bucket_x, int bucket_y, int bucket_index, MFace *mf)
|
||||
{
|
||||
@@ -2036,13 +1964,14 @@ static int project_bucket_face_isect(ProjectPaintState *ps, float min[2], float
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add faces to the bucket but dont initialize its pixels */
|
||||
static void project_paint_delayed_face_init(ProjectPaintState *ps, MFace *mf, MTFace *tf, int face_index)
|
||||
{
|
||||
float min[2], max[2];
|
||||
int bucket_min[2], bucket_max[2]; /* for ps->bucketRect indexing */
|
||||
int i, a, bucket_x, bucket_y, bucket_index;
|
||||
|
||||
int has_x_isect = -1, has_isect = -1; /* for early loop exit */
|
||||
int has_x_isect = -1, has_isect = 0; /* for early loop exit */
|
||||
|
||||
INIT_MINMAX2(min,max);
|
||||
|
||||
@@ -2127,12 +2056,12 @@ static void project_paint_begin( ProjectPaintState *ps, short mval[2])
|
||||
int image_index;
|
||||
|
||||
/* memory sized to add to arena size */
|
||||
int tot_bucketMem=0;
|
||||
int tot_faceSeamFlagMem=0;
|
||||
int tot_bucketRectMem=0;
|
||||
int tot_faceSeamFlagsMem=0;
|
||||
int tot_faceSeamUVMem=0;
|
||||
int tot_faceListMem=0;
|
||||
int tot_bucketFlagMem=0;
|
||||
int tot_bucketVertFacesMem=0;
|
||||
int tot_bucketFacesMem=0;
|
||||
int tot_bucketFlagsMem=0;
|
||||
int tot_vertFacesMem=0;
|
||||
|
||||
/* ---- end defines ---- */
|
||||
|
||||
@@ -2232,48 +2161,48 @@ static void project_paint_begin( ProjectPaintState *ps, short mval[2])
|
||||
CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
|
||||
CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
|
||||
|
||||
tot_bucketMem = sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y;
|
||||
tot_faceListMem = sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y;
|
||||
tot_bucketRectMem = sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y;
|
||||
tot_bucketFacesMem = sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y;
|
||||
|
||||
tot_bucketFlagMem = sizeof(char) * ps->buckets_x * ps->buckets_y;
|
||||
tot_bucketFlagsMem = sizeof(char) * ps->buckets_x * ps->buckets_y;
|
||||
#ifndef PROJ_DEBUG_NOSEAMBLEED
|
||||
if (ps->seam_bleed_px > 0.0) { /* UV Seams for bleeding */
|
||||
tot_bucketVertFacesMem = sizeof(LinkNode *) * ps->dm_totvert;
|
||||
tot_faceSeamFlagMem = sizeof(char) * ps->dm_totface;
|
||||
tot_vertFacesMem = sizeof(LinkNode *) * ps->dm_totvert;
|
||||
tot_faceSeamFlagsMem = sizeof(char) * ps->dm_totface;
|
||||
tot_faceSeamUVMem = sizeof(float) * ps->dm_totface * 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* BLI_memarena_new uses calloc */
|
||||
ps->arena =
|
||||
BLI_memarena_new( tot_bucketMem +
|
||||
tot_faceListMem +
|
||||
tot_faceSeamFlagMem +
|
||||
BLI_memarena_new( tot_bucketRectMem +
|
||||
tot_bucketFacesMem +
|
||||
tot_faceSeamFlagsMem +
|
||||
tot_faceSeamUVMem +
|
||||
tot_bucketVertFacesMem + (1<<18));
|
||||
tot_vertFacesMem + (1<<18));
|
||||
|
||||
BLI_memarena_use_calloc(ps->arena);
|
||||
|
||||
ps->bucketRect = (LinkNode **)BLI_memarena_alloc( ps->arena, tot_bucketMem);
|
||||
ps->bucketFaces= (LinkNode **)BLI_memarena_alloc( ps->arena, tot_faceListMem);
|
||||
ps->bucketRect = (LinkNode **)BLI_memarena_alloc( ps->arena, tot_bucketRectMem);
|
||||
ps->bucketFaces= (LinkNode **)BLI_memarena_alloc( ps->arena, tot_bucketFacesMem);
|
||||
|
||||
ps->bucketFlags= (char *)BLI_memarena_alloc( ps->arena, tot_bucketFlagMem);
|
||||
ps->bucketFlags= (char *)BLI_memarena_alloc( ps->arena, tot_bucketFlagsMem);
|
||||
#ifndef PROJ_DEBUG_NOSEAMBLEED
|
||||
if (ps->seam_bleed_px > 0.0) {
|
||||
ps->vertFaces= (LinkNode **)BLI_memarena_alloc( ps->arena, tot_bucketVertFacesMem);
|
||||
ps->faceSeamFlags = (char *)BLI_memarena_alloc( ps->arena, tot_faceSeamFlagMem);
|
||||
ps->vertFaces= (LinkNode **)BLI_memarena_alloc( ps->arena, tot_vertFacesMem);
|
||||
ps->faceSeamFlags = (char *)BLI_memarena_alloc( ps->arena, tot_faceSeamFlagsMem);
|
||||
ps->faceSeamUVs= BLI_memarena_alloc( ps->arena, tot_faceSeamUVMem);
|
||||
}
|
||||
#endif
|
||||
|
||||
// calloced - memset(ps->bucketRect, 0, tot_bucketMem);
|
||||
// calloced - memset(ps->bucketFaces, 0, tot_faceListMem);
|
||||
// calloced - memset(ps->bucketFlags, 0, tot_bucketFlagMem);
|
||||
// calloced - memset(ps->bucketRect, 0, tot_bucketRectMem);
|
||||
// calloced - memset(ps->bucketFaces, 0, tot_bucketFacesMem);
|
||||
// calloced - memset(ps->bucketFlags, 0, tot_bucketFlagsMem);
|
||||
#ifndef PROJ_DEBUG_NOSEAMBLEED
|
||||
// calloced - memset(ps->faceSeamFlags,0, tot_faceSeamFlagMem);
|
||||
// calloced - memset(ps->faceSeamFlags,0, tot_faceSeamFlagsMem);
|
||||
|
||||
// calloced - if (ps->seam_bleed_px > 0.0) {
|
||||
// calloced - memset(ps->vertFaces, 0, tot_bucketVertFacesMem);
|
||||
// calloced - memset(ps->vertFaces, 0, tot_vertFacesMem);
|
||||
/* TODO dosnt need zeroing? */
|
||||
// calloced - memset(ps->faceSeamUVs, 0, tot_faceSeamUVMem);
|
||||
// calloced - }
|
||||
@@ -2492,7 +2421,8 @@ static void project_paint_end( ProjectPaintState *ps )
|
||||
/* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color
|
||||
* because allocating the tiles allong the way slows down painting */
|
||||
/* TODO float buffer */
|
||||
((unsigned int *)tile->rect)[ (projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE ] = *((unsigned int *)projPixel->origColor);
|
||||
((unsigned int *)tile->rect)[ (projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE ] = *((unsigned int *)projPixel->origColor);
|
||||
|
||||
}
|
||||
|
||||
pixel_node = pixel_node->next;
|
||||
@@ -3199,8 +3129,8 @@ static void imapaint_paint_sub_stroke_project(
|
||||
project_paint_bucket_init(ps, thread_index, bucket_index, bucket_bounds);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
/* TODO - we may want to init clone data in a separate to project_paint_bucket_init
|
||||
* so we don't go overboard and init too many clone pixels */
|
||||
|
||||
if ((node = ps->bucketRect[bucket_index])) {
|
||||
|
||||
@@ -3704,7 +3634,7 @@ void imagepaint_paint(short mousebutton, short texpaint)
|
||||
}
|
||||
|
||||
/* TODO - grease pencil stroke is very basic now and only useful for benchmarking, should make this nicer */
|
||||
//stroke_gp = 1;
|
||||
stroke_gp = 0;
|
||||
/*
|
||||
if (G.rt==123) {
|
||||
|
||||
@@ -3763,16 +3693,25 @@ void imagepaint_paint(short mousebutton, short texpaint)
|
||||
|
||||
if (project) {
|
||||
/* setup projection painting data */
|
||||
ps.do_backfacecull = 1;
|
||||
ps.do_occlude = 1;
|
||||
ps.do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1;
|
||||
ps.do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1;
|
||||
#ifndef PROJ_DEBUG_NOSEAMBLEED
|
||||
ps.seam_bleed_px = 2.0; /* pixel num to bleed */
|
||||
if (settings->imapaint.flag & IMAGEPAINT_PROJECT_IGNORE_SEAMS) {
|
||||
ps.seam_bleed_px = 0.0;
|
||||
} else {
|
||||
ps.seam_bleed_px = settings->imapaint.seam_bleed; /* pixel num to bleed */
|
||||
if (ps.seam_bleed_px < 2.0)
|
||||
ps.seam_bleed_px = 2.0;
|
||||
}
|
||||
|
||||
#endif
|
||||
project_paint_begin(&ps, mval);
|
||||
|
||||
if (stroke_gp) {
|
||||
tot_gp = imapaint_paint_gp_to_stroke(&points_gp);
|
||||
vec_gp = points_gp;
|
||||
prevmval[0]= (short)vec_gp[0];
|
||||
prevmval[1]= (short)vec_gp[1];
|
||||
}
|
||||
|
||||
spacing = ((float)ps.brush->size)/100.0 * ps.brush->spacing;
|
||||
@@ -3811,7 +3750,7 @@ void imagepaint_paint(short mousebutton, short texpaint)
|
||||
}
|
||||
|
||||
init = 0;
|
||||
|
||||
|
||||
} else {
|
||||
if((mval[0] != prevmval[0]) || (mval[1] != prevmval[1])) {
|
||||
imapaint_paint_stroke(&s, painter, texpaint, prevmval, mval, time, pressure);
|
||||
@@ -3840,7 +3779,8 @@ void imagepaint_paint(short mousebutton, short texpaint)
|
||||
if (points_gp)
|
||||
MEM_freeN(points_gp);
|
||||
|
||||
printf("timed test %f\n", (float)(PIL_check_seconds_timer() - benchmark_time));
|
||||
if (stroke_gp)
|
||||
printf("timed test %f\n", (float)(PIL_check_seconds_timer() - benchmark_time));
|
||||
|
||||
imapaint_redraw(1, texpaint, s.image);
|
||||
undo_imagepaint_push_end();
|
||||
|
||||
Reference in New Issue
Block a user