284
/* external functions */
505
/* fast projection bucket array lookup, use the safe version for bound checking */
506
static int project_bucket_offset(const ProjPaintState *ps, const float projCoSS[2])
508
/* If we were not dealing with screenspace 2D coords we could simple do...
509
* ps->bucketRect[x + (y*ps->buckets_y)] */
512
* projCoSS[0] - ps->screenMin[0] : zero origin
513
* ... / ps->screen_width : range from 0.0 to 1.0
514
* ... * ps->buckets_x : use as a bucket index
516
* Second multiplication does similar but for vertical offset
518
return ( (int)(((projCoSS[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x)) +
519
( ( (int)(((projCoSS[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y)) * ps->buckets_x);
522
static int project_bucket_offset_safe(const ProjPaintState *ps, const float projCoSS[2])
524
int bucket_index = project_bucket_offset(ps, projCoSS);
526
if (bucket_index < 0 || bucket_index >= ps->buckets_x*ps->buckets_y) {
534
#define SIDE_OF_LINE(pa, pb, pp) ((pa[0]-pp[0])*(pb[1]-pp[1]))-((pb[0]-pp[0])*(pa[1]-pp[1]))
536
static float AreaSignedF2Dfl(float *v1, float *v2, float *v3)
538
return (float)(0.5f*((v1[0]-v2[0])*(v2[1]-v3[1]) +
539
(v1[1]-v2[1])*(v3[0]-v2[0])));
542
static void BarycentricWeights2f(float pt[2], float v1[2], float v2[2], float v3[2], float w[3])
544
float wtot_inv, wtot;
546
w[0] = AreaSignedF2Dfl(v2, v3, pt);
547
w[1] = AreaSignedF2Dfl(v3, v1, pt);
548
w[2] = AreaSignedF2Dfl(v1, v2, pt);
549
wtot = w[0]+w[1]+w[2];
552
wtot_inv = 1.0f/wtot;
554
w[0] = w[0]*wtot_inv;
555
w[1] = w[1]*wtot_inv;
556
w[2] = w[2]*wtot_inv;
558
else /* dummy values for zero area face */
559
w[0] = w[1] = w[2] = 1.0f/3.0f;
562
/* still use 2D X,Y space but this works for verts transformed by a perspective matrix, using their 4th component as a weight */
563
static void BarycentricWeightsPersp2f(float pt[2], float v1[4], float v2[4], float v3[4], float w[3])
565
float wtot_inv, wtot;
567
w[0] = AreaSignedF2Dfl(v2, v3, pt) / v1[3];
568
w[1] = AreaSignedF2Dfl(v3, v1, pt) / v2[3];
569
w[2] = AreaSignedF2Dfl(v1, v2, pt) / v3[3];
570
wtot = w[0]+w[1]+w[2];
573
wtot_inv = 1.0f/wtot;
575
w[0] = w[0]*wtot_inv;
576
w[1] = w[1]*wtot_inv;
577
w[2] = w[2]*wtot_inv;
579
else /* dummy values for zero area face */
580
w[0] = w[1] = w[2] = 1.0f/3.0f;
583
static void VecWeightf(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3])
585
p[0] = v1[0]*w[0] + v2[0]*w[1] + v3[0]*w[2];
586
p[1] = v1[1]*w[0] + v2[1]*w[1] + v3[1]*w[2];
587
p[2] = v1[2]*w[0] + v2[2]*w[1] + v3[2]*w[2];
590
static void Vec2Weightf(float p[2], const float v1[2], const float v2[2], const float v3[2], const float w[3])
592
p[0] = v1[0]*w[0] + v2[0]*w[1] + v3[0]*w[2];
593
p[1] = v1[1]*w[0] + v2[1]*w[1] + v3[1]*w[2];
596
static float VecZDepthOrtho(float pt[2], float v1[3], float v2[3], float v3[3], float w[3])
598
BarycentricWeights2f(pt, v1, v2, v3, w);
599
return (v1[2]*w[0]) + (v2[2]*w[1]) + (v3[2]*w[2]);
602
static float VecZDepthPersp(float pt[2], float v1[3], float v2[3], float v3[3], float w[3])
604
BarycentricWeightsPersp2f(pt, v1, v2, v3, w);
605
return (v1[2]*w[0]) + (v2[2]*w[1]) + (v3[2]*w[2]);
609
/* Return the top-most face index that the screen space coord 'pt' touches (or -1) */
610
static int project_paint_PickFace(const ProjPaintState *ps, float pt[2], float w[3], int *side)
614
float *v1, *v2, *v3, *v4;
618
int best_face_index = -1;
619
float z_depth_best = MAXFLOAT, z_depth;
622
bucket_index = project_bucket_offset_safe(ps, pt);
623
if (bucket_index==-1)
628
/* we could return 0 for 1 face buckets, as long as this function assumes
629
* that the point its testing is only every originated from an existing face */
631
for (node= ps->bucketFaces[bucket_index]; node; node= node->next) {
632
face_index = GET_INT_FROM_POINTER(node->link);
633
mf= ps->dm_mface + face_index;
635
v1= ps->screenCoords[mf->v1];
636
v2= ps->screenCoords[mf->v2];
637
v3= ps->screenCoords[mf->v3];
639
if (IsectPT2Df(pt, v1, v2, v3)) {
640
if (ps->is_ortho) z_depth= VecZDepthOrtho(pt, v1, v2, v3, w_tmp);
641
else z_depth= VecZDepthPersp(pt, v1, v2, v3, w_tmp);
643
if (z_depth < z_depth_best) {
644
best_face_index = face_index;
646
z_depth_best = z_depth;
651
v4= ps->screenCoords[mf->v4];
653
if (IsectPT2Df(pt, v1, v3, v4)) {
654
if (ps->is_ortho) z_depth= VecZDepthOrtho(pt, v1, v3, v4, w_tmp);
655
else z_depth= VecZDepthPersp(pt, v1, v3, v4, w_tmp);
657
if (z_depth < z_depth_best) {
658
best_face_index = face_index;
660
z_depth_best = z_depth;
668
return best_face_index; /* will be -1 or a valid face */
671
/* Converts a uv coord into a pixel location wrapping if the uv is outside 0-1 range */
672
static void uvco_to_wrapped_pxco(float uv[2], int ibuf_x, int ibuf_y, float *x, float *y)
675
*x = (float)fmodf(uv[0], 1.0f);
676
*y = (float)fmodf(uv[1], 1.0f);
678
if (*x < 0.0f) *x += 1.0f;
679
if (*y < 0.0f) *y += 1.0f;
681
*x = *x * ibuf_x - 0.5f;
682
*y = *y * ibuf_y - 0.5f;
685
/* Set the top-most face color that the screen space coord 'pt' touches (or return 0 if none touch) */
686
static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float *rgba_fp, unsigned char *rgba, const int interp)
696
face_index = project_paint_PickFace(ps, pt, w, &side);
698
if (face_index == -1)
701
tf = ps->dm_mtface + face_index;
704
Vec2Weightf(uv, tf->uv[0], tf->uv[1], tf->uv[2], w);
707
Vec2Weightf(uv, tf->uv[0], tf->uv[2], tf->uv[3], w);
710
ibuf = tf->tpage->ibufs.first; /* we must have got the imbuf before getting here */
715
uvco_to_wrapped_pxco(uv, ibuf->x, ibuf->y, &x, &y);
717
if (ibuf->rect_float) {
719
bilinear_interpolation_color_wrap(ibuf, NULL, rgba_fp, x, y);
723
bilinear_interpolation_color_wrap(ibuf, NULL, rgba_tmp_f, x, y);
724
IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_f);
729
bilinear_interpolation_color_wrap(ibuf, rgba, NULL, x, y);
732
unsigned char rgba_tmp[4];
733
bilinear_interpolation_color_wrap(ibuf, rgba_tmp, NULL, x, y);
734
IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, rgba_tmp);
739
xi = (uv[0]*ibuf->x) + 0.5f;
740
yi = (uv[1]*ibuf->y) + 0.5f;
742
//if (xi<0 || xi>=ibuf->x || yi<0 || yi>=ibuf->y) return 0;
745
xi = ((int)(uv[0]*ibuf->x)) % ibuf->x;
746
if (xi<0) xi += ibuf->x;
747
yi = ((int)(uv[1]*ibuf->y)) % ibuf->y;
748
if (yi<0) yi += ibuf->y;
752
if (ibuf->rect_float) {
753
float *rgba_tmp_fp = ibuf->rect_float + (xi + yi * ibuf->x * 4);
754
IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_fp);
757
*((unsigned int *)rgba) = *(unsigned int *)(((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4));
762
if (ibuf->rect_float) {
763
QUATCOPY(rgba_fp, ((float *)ibuf->rect_float + ((xi + yi * ibuf->x) * 4)));
766
char *tmp_ch= ((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4);
767
IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, tmp_ch);
774
/* Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusuion test)
777
* -1 : no occlusion but 2D intersection is true (avoid testing the other half of a quad)
779
2 : occluded with w[3] weights set (need to know in some cases) */
781
static int project_paint_occlude_ptv(float pt[3], float v1[3], float v2[3], float v3[3], float w[3], int is_ortho)
783
/* if all are behind us, return false */
784
if(v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2])
787
/* do a 2D point in try intersection */
788
if (!IsectPT2Df(pt, v1, v2, v3))
789
return 0; /* we know there is */
792
/* From here on we know there IS an intersection */
793
/* if ALL of the verts are infront of us then we know it intersects ? */
794
if(v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) {
798
/* we intersect? - find the exact depth at the point of intersection */
799
/* Is this point is occluded by another face? */
801
if (VecZDepthOrtho(pt, v1, v2, v3, w) < pt[2]) return 2;
804
if (VecZDepthPersp(pt, v1, v2, v3, w) < pt[2]) return 2;
811
static int project_paint_occlude_ptv_clip(
812
const ProjPaintState *ps, const MFace *mf,
813
float pt[3], float v1[3], float v2[3], float v3[3],
817
int ret = project_paint_occlude_ptv(pt, v1, v2, v3, w, ps->is_ortho);
822
if (ret==1) { /* weights not calculated */
823
if (ps->is_ortho) BarycentricWeights2f(pt, v1, v2, v3, w);
824
else BarycentricWeightsPersp2f(pt, v1, v2, v3, w);
827
/* Test if we're in the clipped area, */
828
if (side) VecWeightf(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
829
else VecWeightf(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
831
Mat4MulVecfl(ps->ob->obmat, wco);
832
if(!view3d_test_clipping(G.vd, wco)) {
840
/* Check if a screenspace location is occluded by any other faces
841
* check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be used for comparison
842
* and dosn't need to be correct in relation to X and Y coords (this is the case in perspective view) */
843
static int project_bucket_point_occluded(const ProjPaintState *ps, LinkNode *bucketFace, const int orig_face, float pixelScreenCo[4])
848
float w[3]; /* not needed when clipping */
850
/* we could return 0 for 1 face buckets, as long as this function assumes
851
* that the point its testing is only every originated from an existing face */
853
for (; bucketFace; bucketFace = bucketFace->next) {
854
face_index = (int)bucketFace->link;
856
if (orig_face != face_index) {
857
mf = ps->dm_mface + face_index;
858
if(G.vd->flag & V3D_CLIPPING)
859
isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], 0);
861
isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], w, ps->is_ortho);
863
/* Note, if isect_ret==-1 then we dont want to test the other side of the quad */
864
if (isect_ret==0 && mf->v4) {
865
if(G.vd->flag & V3D_CLIPPING)
866
isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], 1);
868
isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], w, ps->is_ortho);
871
/* TODO - we may want to cache the first hit,
872
* it is not possible to swap the face order in the list anymore */
880
/* basic line intersection, could move to arithb.c, 2 points with a horiz line
881
* 1 for an intersection, 2 if the first point is aligned, 3 if the second point is aligned */
883
#define ISECT_TRUE_P1 2
884
#define ISECT_TRUE_P2 3
885
static int line_isect_y(const float p1[2], const float p2[2], const float y_level, float *x_isect)
889
if (y_level==p1[1]) { /* are we touching the first point? - no interpolation needed */
891
return ISECT_TRUE_P1;
893
if (y_level==p2[1]) { /* are we touching the second point? - no interpolation needed */
895
return ISECT_TRUE_P2;
898
y_diff= fabsf(p1[1]-p2[1]); /* yuck, horizontal line, we cant do much here */
900
if (y_diff < 0.000001f) {
901
*x_isect = (p1[0]+p2[0]) * 0.5f;
905
if (p1[1] > y_level && p2[1] < y_level) {
906
*x_isect = (p2[0]*(p1[1]-y_level) + p1[0]*(y_level-p2[1])) / y_diff; /*(p1[1]-p2[1]);*/
909
else if (p1[1] < y_level && p2[1] > y_level) {
910
*x_isect = (p2[0]*(y_level-p1[1]) + p1[0]*(p2[1]-y_level)) / y_diff; /*(p2[1]-p1[1]);*/
918
static int line_isect_x(const float p1[2], const float p2[2], const float x_level, float *y_isect)
922
if (x_level==p1[0]) { /* are we touching the first point? - no interpolation needed */
924
return ISECT_TRUE_P1;
926
if (x_level==p2[0]) { /* are we touching the second point? - no interpolation needed */
928
return ISECT_TRUE_P2;
931
x_diff= fabsf(p1[0]-p2[0]); /* yuck, horizontal line, we cant do much here */
933
if (x_diff < 0.000001) { /* yuck, vertical line, we cant do much here */
934
*y_isect = (p1[0]+p2[0]) * 0.5f;
938
if (p1[0] > x_level && p2[0] < x_level) {
939
*y_isect = (p2[1]*(p1[0]-x_level) + p1[1]*(x_level-p2[0])) / x_diff; /*(p1[0]-p2[0]);*/
942
else if (p1[0] < x_level && p2[0] > x_level) {
943
*y_isect = (p2[1]*(x_level-p1[0]) + p1[1]*(p2[0]-x_level)) / x_diff; /*(p2[0]-p1[0]);*/
951
/* simple func use for comparing UV locations to check if there are seams.
952
* Its possible this gives incorrect results, when the UVs for 1 face go into the next
953
* tile, but do not do this for the adjacent face, it could return a false positive.
954
* This is so unlikely that Id not worry about it. */
955
#ifndef PROJ_DEBUG_NOSEAMBLEED
956
static int cmp_uv(const float vec2a[2], const float vec2b[2])
958
/* if the UV's are not between 0.0 and 1.0 */
959
float xa = (float)fmodf(vec2a[0], 1.0f);
960
float ya = (float)fmodf(vec2a[1], 1.0f);
962
float xb = (float)fmodf(vec2b[0], 1.0f);
963
float yb = (float)fmodf(vec2b[1], 1.0f);
965
if (xa < 0.0f) xa += 1.0f;
966
if (ya < 0.0f) ya += 1.0f;
968
if (xb < 0.0f) xb += 1.0f;
969
if (yb < 0.0f) yb += 1.0f;
971
return ((fabsf(xa-xb) < PROJ_GEOM_TOLERANCE) && (fabsf(ya-yb) < PROJ_GEOM_TOLERANCE)) ? 1:0;
975
/* set min_px and max_px to the image space bounds of the UV coords
976
* return zero if there is no area in the returned rectangle */
977
#ifndef PROJ_DEBUG_NOSEAMBLEED
978
static int pixel_bounds_uv(
979
const float uv1[2], const float uv2[2], const float uv3[2], const float uv4[2],
981
const int ibuf_x, const int ibuf_y,
984
float min_uv[2], max_uv[2]; /* UV bounds */
986
INIT_MINMAX2(min_uv, max_uv);
988
DO_MINMAX2(uv1, min_uv, max_uv);
989
DO_MINMAX2(uv2, min_uv, max_uv);
990
DO_MINMAX2(uv3, min_uv, max_uv);
992
DO_MINMAX2(uv4, min_uv, max_uv);
994
bounds_px->xmin = (int)(ibuf_x * min_uv[0]);
995
bounds_px->ymin = (int)(ibuf_y * min_uv[1]);
997
bounds_px->xmax = (int)(ibuf_x * max_uv[0]) +1;
998
bounds_px->ymax = (int)(ibuf_y * max_uv[1]) +1;
1000
/*printf("%d %d %d %d \n", min_px[0], min_px[1], max_px[0], max_px[1]);*/
1002
/* face uses no UV area when quantized to pixels? */
1003
return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1;
1007
static int pixel_bounds_array(float (* uv)[2], rcti *bounds_px, const int ibuf_x, const int ibuf_y, int tot)
1009
float min_uv[2], max_uv[2]; /* UV bounds */
1015
INIT_MINMAX2(min_uv, max_uv);
1018
DO_MINMAX2((*uv), min_uv, max_uv);
1022
bounds_px->xmin = (int)(ibuf_x * min_uv[0]);
1023
bounds_px->ymin = (int)(ibuf_y * min_uv[1]);
1025
bounds_px->xmax = (int)(ibuf_x * max_uv[0]) +1;
1026
bounds_px->ymax = (int)(ibuf_y * max_uv[1]) +1;
1028
/*printf("%d %d %d %d \n", min_px[0], min_px[1], max_px[0], max_px[1]);*/
1030
/* face uses no UV area when quantized to pixels? */
1031
return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1;
1034
#ifndef PROJ_DEBUG_NOSEAMBLEED
1036
/* This function returns 1 if this face has a seam along the 2 face-vert indicies
1037
* 'orig_i1_fidx' and 'orig_i2_fidx' */
1038
static int check_seam(const ProjPaintState *ps, const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx, int *other_face, int *orig_fidx)
1043
int i1_fidx = -1, i2_fidx = -1; /* index in face */
1046
const MFace *orig_mf = ps->dm_mface + orig_face;
1047
const MTFace *orig_tf = ps->dm_mtface + orig_face;
1049
/* vert indicies from face vert order indicies */
1050
i1 = (*(&orig_mf->v1 + orig_i1_fidx));
1051
i2 = (*(&orig_mf->v1 + orig_i2_fidx));
1053
for (node = ps->vertFaces[i1]; node; node = node->next) {
1054
face_index = (int)node->link;
1055
if (face_index != orig_face) {
1056
mf = ps->dm_mface + face_index;
1057
/* could check if the 2 faces images match here,
1058
* but then there wouldn't be a way to return the opposite face's info */
1061
/* We need to know the order of the verts in the adjacent face
1062
* set the i1_fidx and i2_fidx to (0,1,2,3) */
1063
if (mf->v1==i1) i1_fidx = 0;
1064
else if (mf->v2==i1) i1_fidx = 1;
1065
else if (mf->v3==i1) i1_fidx = 2;
1066
else if (mf->v4 && mf->v4==i1) i1_fidx = 3;
1068
if (mf->v1==i2) i2_fidx = 0;
1069
else if (mf->v2==i2) i2_fidx = 1;
1070
else if (mf->v3==i2) i2_fidx = 2;
1071
else if (mf->v4 && mf->v4==i2) i2_fidx = 3;
1073
/* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */
1074
if (i2_fidx != -1) {
1075
/* This IS an adjacent face!, now lets check if the UVs are ok */
1076
tf = ps->dm_mtface + face_index;
1078
/* set up the other face */
1079
*other_face = face_index;
1080
*orig_fidx = (i1_fidx < i2_fidx) ? i1_fidx : i2_fidx;
1082
/* first test if they have the same image */
1083
if ( (orig_tf->tpage == tf->tpage) &&
1084
cmp_uv(orig_tf->uv[orig_i1_fidx], tf->uv[i1_fidx]) &&
1085
cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]) )
1087
// printf("SEAM (NONE)\n");
1092
// printf("SEAM (UV GAP)\n");
1098
// printf("SEAM (NO FACE)\n");
1103
/* TODO - move to arithb.c */
1104
/* Converts an angle to a length that can be used for maintaining an even margin around UV's */
1105
static float angleToLength(float angle)
1107
// already accounted for
1108
if (angle < 0.000001f) {
1112
return fabsf(1.0f / cosf(angle * (M_PI/180.0f)));
1116
/* Calculate outset UV's, this is not the same as simply scaling the UVs,
1117
* since the outset coords are a margin that keep an even distance from the original UV's,
1118
* note that the image aspect is taken into account */
1119
static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const float scaler, const int ibuf_x, const int ibuf_y, const int is_quad)
1121
float a1, a2, a3, a4=0.0f;
1122
float puv[4][2]; /* pixelspace uv's */
1123
float no1[2], no2[2], no3[2], no4[2]; /* normals */
1124
float dir1[2], dir2[2], dir3[2], dir4[2];
1125
float ibuf_x_inv = 1.0f / (float)ibuf_x;
1126
float ibuf_y_inv = 1.0f / (float)ibuf_y;
1128
/* make UV's in pixel space so we can */
1129
puv[0][0] = orig_uv[0][0] * ibuf_x;
1130
puv[0][1] = orig_uv[0][1] * ibuf_y;
1132
puv[1][0] = orig_uv[1][0] * ibuf_x;
1133
puv[1][1] = orig_uv[1][1] * ibuf_y;
1135
puv[2][0] = orig_uv[2][0] * ibuf_x;
1136
puv[2][1] = orig_uv[2][1] * ibuf_y;
1139
puv[3][0] = orig_uv[3][0] * ibuf_x;
1140
puv[3][1] = orig_uv[3][1] * ibuf_y;
1143
/* face edge directions */
1144
Vec2Subf(dir1, puv[1], puv[0]);
1145
Vec2Subf(dir2, puv[2], puv[1]);
1150
Vec2Subf(dir3, puv[3], puv[2]);
1151
Vec2Subf(dir4, puv[0], puv[3]);
1156
Vec2Subf(dir3, puv[0], puv[2]);
1161
a1 = angleToLength(NormalizedVecAngle2_2D(dir4, dir1));
1162
a2 = angleToLength(NormalizedVecAngle2_2D(dir1, dir2));
1163
a3 = angleToLength(NormalizedVecAngle2_2D(dir2, dir3));
1164
a4 = angleToLength(NormalizedVecAngle2_2D(dir3, dir4));
1167
a1 = angleToLength(NormalizedVecAngle2_2D(dir3, dir1));
1168
a2 = angleToLength(NormalizedVecAngle2_2D(dir1, dir2));
1169
a3 = angleToLength(NormalizedVecAngle2_2D(dir2, dir3));
1173
Vec2Subf(no1, dir4, dir1);
1174
Vec2Subf(no2, dir1, dir2);
1175
Vec2Subf(no3, dir2, dir3);
1176
Vec2Subf(no4, dir3, dir4);
1181
Vec2Mulf(no1, a1*scaler);
1182
Vec2Mulf(no2, a2*scaler);
1183
Vec2Mulf(no3, a3*scaler);
1184
Vec2Mulf(no4, a4*scaler);
1185
Vec2Addf(outset_uv[0], puv[0], no1);
1186
Vec2Addf(outset_uv[1], puv[1], no2);
1187
Vec2Addf(outset_uv[2], puv[2], no3);
1188
Vec2Addf(outset_uv[3], puv[3], no4);
1189
outset_uv[0][0] *= ibuf_x_inv;
1190
outset_uv[0][1] *= ibuf_y_inv;
1192
outset_uv[1][0] *= ibuf_x_inv;
1193
outset_uv[1][1] *= ibuf_y_inv;
1195
outset_uv[2][0] *= ibuf_x_inv;
1196
outset_uv[2][1] *= ibuf_y_inv;
1198
outset_uv[3][0] *= ibuf_x_inv;
1199
outset_uv[3][1] *= ibuf_y_inv;
1202
Vec2Subf(no1, dir3, dir1);
1203
Vec2Subf(no2, dir1, dir2);
1204
Vec2Subf(no3, dir2, dir3);
1208
Vec2Mulf(no1, a1*scaler);
1209
Vec2Mulf(no2, a2*scaler);
1210
Vec2Mulf(no3, a3*scaler);
1211
Vec2Addf(outset_uv[0], puv[0], no1);
1212
Vec2Addf(outset_uv[1], puv[1], no2);
1213
Vec2Addf(outset_uv[2], puv[2], no3);
1214
outset_uv[0][0] *= ibuf_x_inv;
1215
outset_uv[0][1] *= ibuf_y_inv;
1217
outset_uv[1][0] *= ibuf_x_inv;
1218
outset_uv[1][1] *= ibuf_y_inv;
1220
outset_uv[2][0] *= ibuf_x_inv;
1221
outset_uv[2][1] *= ibuf_y_inv;
1226
* Be tricky with flags, first 4 bits are PROJ_FACE_SEAM1 to 4, last 4 bits are PROJ_FACE_NOSEAM1 to 4
1227
* 1<<i - where i is (0-3)
1229
* If we're multithreadng, make sure threads are locked when this is called
1231
static void project_face_seams_init(const ProjPaintState *ps, const int face_index, const int is_quad)
1233
int other_face, other_fidx; /* vars for the other face, we also set its flag */
1234
int fidx1 = is_quad ? 3 : 2;
1235
int fidx2 = 0; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) or (0,1,2) -> (1,2,0) for a tri */
1238
if ((ps->faceSeamFlags[face_index] & (1<<fidx1|16<<fidx1)) == 0) {
1239
if (check_seam(ps, face_index, fidx1, fidx2, &other_face, &other_fidx)) {
1240
ps->faceSeamFlags[face_index] |= 1<<fidx1;
1241
if (other_face != -1)
1242
ps->faceSeamFlags[other_face] |= 1<<other_fidx;
1245
ps->faceSeamFlags[face_index] |= 16<<fidx1;
1246
if (other_face != -1)
1247
ps->faceSeamFlags[other_face] |= 16<<other_fidx; /* second 4 bits for disabled */
1254
#endif // PROJ_DEBUG_NOSEAMBLEED
1257
/* TODO - move to arithb.c */
1259
/* little sister we only need to know lambda */
1260
static float lambda_cp_line2(const float p[2], const float l1[2], const float l2[2])
1264
u[0] = l2[0] - l1[0];
1265
u[1] = l2[1] - l1[1];
1267
h[0] = p[0] - l1[0];
1268
h[1] = p[1] - l1[1];
1270
return(Inp2f(u, h)/Inp2f(u, u));
1274
/* Converts a UV location to a 3D screenspace location
1275
* Takes a 'uv' and 3 UV coords, and sets the values of pixelScreenCo
1277
* This is used for finding a pixels location in screenspace for painting */
1278
static void screen_px_from_ortho(
1280
float v1co[3], float v2co[3], float v3co[3], /* Screenspace coords */
1281
float uv1co[2], float uv2co[2], float uv3co[2],
1282
float pixelScreenCo[4],
1285
BarycentricWeights2f(uv, uv1co, uv2co, uv3co, w);
1286
VecWeightf(pixelScreenCo, v1co, v2co, v3co, w);
1289
/* same as screen_px_from_ortho except we need to take into account
1290
* the perspective W coord for each vert */
1291
static void screen_px_from_persp(
1293
float v1co[3], float v2co[3], float v3co[3], /* screenspace coords */
1294
float uv1co[2], float uv2co[2], float uv3co[2],
1295
float pixelScreenCo[4],
1299
float wtot_inv, wtot;
1300
BarycentricWeights2f(uv, uv1co, uv2co, uv3co, w);
1302
/* re-weight from the 4th coord of each screen vert */
1307
wtot = w[0]+w[1]+w[2];
1310
wtot_inv = 1.0f / wtot;
1316
w[0] = w[1] = w[2] = 1.0/3.0; /* dummy values for zero area face */
1318
/* done re-weighting */
1320
VecWeightf(pixelScreenCo, v1co, v2co, v3co, w);
1323
static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const float w[3], int side, unsigned char rgba_ub[4], float rgba_f[4])
1325
float *uvCo1, *uvCo2, *uvCo3;
1326
float uv_other[2], x, y;
1328
uvCo1 = (float *)tf_other->uv[0];
1330
uvCo2 = (float *)tf_other->uv[2];
1331
uvCo3 = (float *)tf_other->uv[3];
1334
uvCo2 = (float *)tf_other->uv[1];
1335
uvCo3 = (float *)tf_other->uv[2];
1338
Vec2Weightf(uv_other, uvCo1, uvCo2, uvCo3, w);
1341
uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y);
1344
if (ibuf_other->rect_float) { /* from float to float */
1345
bilinear_interpolation_color_wrap(ibuf_other, NULL, rgba_f, x, y);
1347
else { /* from char to float */
1348
bilinear_interpolation_color_wrap(ibuf_other, rgba_ub, NULL, x, y);
1353
/* run this outside project_paint_uvpixel_init since pixels with mask 0 dont need init */
1354
float project_paint_uvpixel_mask(
1355
const ProjPaintState *ps,
1356
const int face_index,
1363
if (ps->do_layer_mask) {
1364
/* another UV layers image is masking this one's */
1366
const MTFace *tf_other = ps->dm_mtface_mask + face_index;
1368
if (tf_other->tpage && (ibuf_other = BKE_image_get_ibuf(tf_other->tpage, NULL))) {
1369
/* BKE_image_get_ibuf - TODO - this may be slow */
1370
unsigned char rgba_ub[4];
1373
project_face_pixel(tf_other, ibuf_other, w, side, rgba_ub, rgba_f);
1375
if (ibuf_other->rect_float) { /* from float to float */
1376
mask = ((rgba_f[0]+rgba_f[1]+rgba_f[2])/3.0f) * rgba_f[3];
1378
else { /* from char to float */
1379
mask = ((rgba_ub[0]+rgba_ub[1]+rgba_ub[2])/(256*3.0f)) * (rgba_ub[3]/256.0f);
1382
if (!ps->do_layer_mask_inv) /* matching the gimps layer mask black/white rules, white==full opacity */
1383
mask = (1.0f - mask);
1396
/* calculate mask */
1397
if (ps->do_mask_normal) {
1398
MFace *mf = ps->dm_mface + face_index;
1399
short *no1, *no2, *no3;
1401
no1 = ps->dm_mvert[mf->v1].no;
1403
no2 = ps->dm_mvert[mf->v3].no;
1404
no3 = ps->dm_mvert[mf->v4].no;
1407
no2 = ps->dm_mvert[mf->v2].no;
1408
no3 = ps->dm_mvert[mf->v3].no;
1411
no[0] = w[0]*no1[0] + w[1]*no2[0] + w[2]*no3[0];
1412
no[1] = w[0]*no1[1] + w[1]*no2[1] + w[2]*no3[1];
1413
no[2] = w[0]*no1[2] + w[1]*no2[2] + w[2]*no3[2];
1416
/* now we can use the normal as a mask */
1418
angle = NormalizedVecAngle2((float *)ps->viewDir, no);
1421
/* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */
1422
float viewDirPersp[3];
1423
float *co1, *co2, *co3;
1424
co1 = ps->dm_mvert[mf->v1].co;
1426
co2 = ps->dm_mvert[mf->v3].co;
1427
co3 = ps->dm_mvert[mf->v4].co;
1430
co2 = ps->dm_mvert[mf->v2].co;
1431
co3 = ps->dm_mvert[mf->v3].co;
1434
/* Get the direction from the viewPoint to the pixel and normalize */
1435
viewDirPersp[0] = (ps->viewPos[0] - (w[0]*co1[0] + w[1]*co2[0] + w[2]*co3[0]));
1436
viewDirPersp[1] = (ps->viewPos[1] - (w[0]*co1[1] + w[1]*co2[1] + w[2]*co3[1]));
1437
viewDirPersp[2] = (ps->viewPos[2] - (w[0]*co1[2] + w[1]*co2[2] + w[2]*co3[2]));
1438
Normalize(viewDirPersp);
1440
angle = NormalizedVecAngle2(viewDirPersp, no);
1443
if (angle >= ps->normal_angle) {
1444
return 0.0f; /* outsize the normal limit*/
1446
else if (angle > ps->normal_angle_inner) {
1447
mask *= (ps->normal_angle - angle) / ps->normal_angle_range;
1448
} /* otherwise no mask normal is needed, were within the limit */
1451
// This only works when the opacity dosnt change while painting, stylus pressure messes with this
1453
// if (ps->is_airbrush==0) mask *= ps->brush->alpha;
1458
/* run this function when we know a bucket's, face's pixel can be initialized,
1459
* return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */
1460
static ProjPixel *project_paint_uvpixel_init(
1461
const ProjPaintState *ps,
1464
short x_px, short y_px,
1466
const int face_index,
1467
const int image_index,
1468
const float pixelScreenCo[4],
1472
ProjPixel *projPixel;
1475
/* wrap pixel location */
1476
x_px = x_px % ibuf->x;
1477
if (x_px<0) x_px += ibuf->x;
1478
y_px = y_px % ibuf->y;
1479
if (y_px<0) y_px += ibuf->y;
1481
if (ps->tool==PAINT_TOOL_CLONE) {
1482
size = sizeof(ProjPixelClone);
1484
else if (ps->tool==PAINT_TOOL_SMEAR) {
1485
size = sizeof(ProjPixelClone);
1488
size = sizeof(ProjPixel);
1491
projPixel = (ProjPixel *)BLI_memarena_alloc(arena, size);
1492
//memset(projPixel, 0, size);
1494
if (ibuf->rect_float) {
1495
projPixel->pixel.f_pt = (float *)ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4);
1496
projPixel->origColor.f[0] = projPixel->newColor.f[0] = projPixel->pixel.f_pt[0];
1497
projPixel->origColor.f[1] = projPixel->newColor.f[1] = projPixel->pixel.f_pt[1];
1498
projPixel->origColor.f[2] = projPixel->newColor.f[2] = projPixel->pixel.f_pt[2];
1499
projPixel->origColor.f[3] = projPixel->newColor.f[3] = projPixel->pixel.f_pt[3];
1502
projPixel->pixel.ch_pt = ((unsigned char *)ibuf->rect + ((x_px + y_px * ibuf->x) * 4));
1503
projPixel->origColor.uint = projPixel->newColor.uint = *projPixel->pixel.uint_pt;
1506
/* screenspace unclamped, we could keep its z and w values but dont need them at the moment */
1507
VECCOPY2D(projPixel->projCoSS, pixelScreenCo);
1509
projPixel->x_px = x_px;
1510
projPixel->y_px = y_px;
1512
projPixel->mask = (unsigned short)(mask * 65535);
1513
projPixel->mask_max = 0;
1515
/* which bounding box cell are we in?, needed for undo */
1516
projPixel->bb_cell_index = ((int)(((float)x_px/(float)ibuf->x) * PROJ_BOUNDBOX_DIV)) + ((int)(((float)y_px/(float)ibuf->y) * PROJ_BOUNDBOX_DIV)) * PROJ_BOUNDBOX_DIV ;
1518
/* done with view3d_project_float inline */
1519
if (ps->tool==PAINT_TOOL_CLONE) {
1520
if (ps->dm_mtface_clone) {
1522
const MTFace *tf_other = ps->dm_mtface_clone + face_index;
1524
if (tf_other->tpage && (ibuf_other = BKE_image_get_ibuf(tf_other->tpage, NULL))) {
1525
/* BKE_image_get_ibuf - TODO - this may be slow */
1527
if (ibuf->rect_float) {
1528
if (ibuf_other->rect_float) { /* from float to float */
1529
project_face_pixel(tf_other, ibuf_other, w, side, NULL, ((ProjPixelClone *)projPixel)->clonepx.f);
1531
else { /* from char to float */
1532
unsigned char rgba_ub[4];
1533
project_face_pixel(tf_other, ibuf_other, w, side, rgba_ub, NULL);
1534
IMAPAINT_CHAR_RGBA_TO_FLOAT(((ProjPixelClone *)projPixel)->clonepx.f, rgba_ub);
1538
if (ibuf_other->rect_float) { /* float to char */
1540
project_face_pixel(tf_other, ibuf_other, w, side, NULL, rgba);
1541
IMAPAINT_FLOAT_RGBA_TO_CHAR(((ProjPixelClone *)projPixel)->clonepx.ch, rgba)
1543
else { /* char to char */
1544
project_face_pixel(tf_other, ibuf_other, w, side, ((ProjPixelClone *)projPixel)->clonepx.ch, NULL);
1549
if (ibuf->rect_float) {
1550
((ProjPixelClone *)projPixel)->clonepx.f[3] = 0;
1553
((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0;
1560
Vec2Subf(co, projPixel->projCoSS, (float *)ps->cloneOffset);
1562
/* no need to initialize the bucket, we're only checking buckets faces and for this
1563
* the faces are alredy initialized in project_paint_delayed_face_init(...) */
1564
if (ibuf->rect_float) {
1565
if (!project_paint_PickColor(ps, co, ((ProjPixelClone *)projPixel)->clonepx.f, NULL, 1)) {
1566
((ProjPixelClone *)projPixel)->clonepx.f[3] = 0; /* zero alpha - ignore */
1570
if (!project_paint_PickColor(ps, co, NULL, ((ProjPixelClone *)projPixel)->clonepx.ch, 1)) {
1571
((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0; /* zero alpha - ignore */
1577
#ifdef PROJ_DEBUG_PAINT
1578
if (ibuf->rect_float) projPixel->pixel.f_pt[0] = 0;
1579
else projPixel->pixel.ch_pt[0] = 0;
1581
projPixel->image_index = image_index;
1586
static int line_clip_rect2f(
1588
const float l1[2], const float l2[2],
1589
float l1_clip[2], float l2_clip[2])
1591
/* first account for horizontal, then vertical lines */
1593
if (fabsf(l1[1]-l2[1]) < PROJ_GEOM_TOLERANCE) {
1594
/* is the line out of range on its Y axis? */
1595
if (l1[1] < rect->ymin || l1[1] > rect->ymax) {
1598
/* line is out of range on its X axis */
1599
if ((l1[0] < rect->xmin && l2[0] < rect->xmin) || (l1[0] > rect->xmax && l2[0] > rect->xmax)) {
1604
if (fabsf(l1[0]-l2[0]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/
1605
if (BLI_in_rctf(rect, l1[0], l1[1])) {
1606
VECCOPY2D(l1_clip, l1);
1607
VECCOPY2D(l2_clip, l2);
1615
VECCOPY2D(l1_clip, l1);
1616
VECCOPY2D(l2_clip, l2);
1617
CLAMP(l1_clip[0], rect->xmin, rect->xmax);
1618
CLAMP(l2_clip[0], rect->xmin, rect->xmax);
1621
else if (fabsf(l1[0]-l2[0]) < PROJ_GEOM_TOLERANCE) {
1622
/* is the line out of range on its X axis? */
1623
if (l1[0] < rect->xmin || l1[0] > rect->xmax) {
1627
/* line is out of range on its Y axis */
1628
if ((l1[1] < rect->ymin && l2[1] < rect->ymin) || (l1[1] > rect->ymax && l2[1] > rect->ymax)) {
1632
if (fabsf(l1[1]-l2[1]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/
1633
if (BLI_in_rctf(rect, l1[0], l1[1])) {
1634
VECCOPY2D(l1_clip, l1);
1635
VECCOPY2D(l2_clip, l2);
1643
VECCOPY2D(l1_clip, l1);
1644
VECCOPY2D(l2_clip, l2);
1645
CLAMP(l1_clip[1], rect->ymin, rect->ymax);
1646
CLAMP(l2_clip[1], rect->ymin, rect->ymax);
1654
/* Done with vertical lines */
1656
/* are either of the points inside the rectangle ? */
1657
if (BLI_in_rctf(rect, l1[0], l1[1])) {
1658
VECCOPY2D(l1_clip, l1);
1662
if (BLI_in_rctf(rect, l2[0], l2[1])) {
1663
VECCOPY2D(l2_clip, l2);
1667
/* line inside rect */
1668
if (ok1 && ok2) return 1;
1671
if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) {
1672
if (l1[1] < l2[1]) { /* line 1 is outside */
1674
l1_clip[1] = rect->ymin;
1679
l2_clip[1] = rect->ymin;
1684
if (ok1 && ok2) return 1;
1686
if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) {
1687
if (l1[1] > l2[1]) { /* line 1 is outside */
1689
l1_clip[1] = rect->ymax;
1694
l2_clip[1] = rect->ymax;
1699
if (ok1 && ok2) return 1;
1702
if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) {
1703
if (l1[0] < l2[0]) { /* line 1 is outside */
1704
l1_clip[0] = rect->xmin;
1709
l2_clip[0] = rect->xmin;
1715
if (ok1 && ok2) return 1;
1717
if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) {
1718
if (l1[0] > l2[0]) { /* line 1 is outside */
1719
l1_clip[0] = rect->xmax;
1724
l2_clip[0] = rect->xmax;
1741
/* scale the quad & tri about its center
1742
* scaling by PROJ_FACE_SCALE_SEAM (0.99x) is used for getting fake UV pixel coords that are on the
1743
* edge of the face but slightly inside it occlusion tests dont return hits on adjacent faces */
1744
static void scale_quad(float insetCos[4][3], float *origCos[4], const float inset)
1747
cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0] + origCos[3][0]) / 4.0f;
1748
cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1] + origCos[3][1]) / 4.0f;
1749
cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2] + origCos[3][2]) / 4.0f;
1751
VecSubf(insetCos[0], origCos[0], cent);
1752
VecSubf(insetCos[1], origCos[1], cent);
1753
VecSubf(insetCos[2], origCos[2], cent);
1754
VecSubf(insetCos[3], origCos[3], cent);
1756
VecMulf(insetCos[0], inset);
1757
VecMulf(insetCos[1], inset);
1758
VecMulf(insetCos[2], inset);
1759
VecMulf(insetCos[3], inset);
1761
VecAddf(insetCos[0], insetCos[0], cent);
1762
VecAddf(insetCos[1], insetCos[1], cent);
1763
VecAddf(insetCos[2], insetCos[2], cent);
1764
VecAddf(insetCos[3], insetCos[3], cent);
1768
static void scale_tri(float insetCos[4][3], float *origCos[4], const float inset)
1771
cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0]) / 3.0f;
1772
cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1]) / 3.0f;
1773
cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2]) / 3.0f;
1775
VecSubf(insetCos[0], origCos[0], cent);
1776
VecSubf(insetCos[1], origCos[1], cent);
1777
VecSubf(insetCos[2], origCos[2], cent);
1779
VecMulf(insetCos[0], inset);
1780
VecMulf(insetCos[1], inset);
1781
VecMulf(insetCos[2], inset);
1783
VecAddf(insetCos[0], insetCos[0], cent);
1784
VecAddf(insetCos[1], insetCos[1], cent);
1785
VecAddf(insetCos[2], insetCos[2], cent);
1789
static float Vec2Lenf_nosqrt(const float *v1, const float *v2)
1798
static float Vec2Lenf_nosqrt_other(const float *v1, const float v2_1, const float v2_2)
1807
/* note, use a squared value so we can use Vec2Lenf_nosqrt
1808
* be sure that you have done a bounds check first or this may fail */
1809
/* only give bucket_bounds as an arg because we need it elsewhere */
1810
static int project_bucket_isect_circle(const int bucket_x, const int bucket_y, const float cent[2], const float radius_squared, rctf *bucket_bounds)
1813
/* Would normally to a simple intersection test, however we know the bounds of these 2 alredy intersect
1814
* so we only need to test if the center is inside the vertical or horizontal bounds on either axis,
1815
* this is even less work then an intersection test
1817
if (BLI_in_rctf(bucket_bounds, cent[0], cent[1]))
1821
if((bucket_bounds->xmin <= cent[0] && bucket_bounds->xmax >= cent[0]) || (bucket_bounds->ymin <= cent[1] && bucket_bounds->ymax >= cent[1]) ) {
1825
/* out of bounds left */
1826
if (cent[0] < bucket_bounds->xmin) {
1827
/* lower left out of radius test */
1828
if (cent[1] < bucket_bounds->ymin) {
1829
return (Vec2Lenf_nosqrt_other(cent, bucket_bounds->xmin, bucket_bounds->ymin) < radius_squared) ? 1 : 0;
1832
else if (cent[1] > bucket_bounds->ymax) {
1833
return (Vec2Lenf_nosqrt_other(cent, bucket_bounds->xmin, bucket_bounds->ymax) < radius_squared) ? 1 : 0;
1836
else if (cent[0] > bucket_bounds->xmax) {
1837
/* lower right out of radius test */
1838
if (cent[1] < bucket_bounds->ymin) {
1839
return (Vec2Lenf_nosqrt_other(cent, bucket_bounds->xmax, bucket_bounds->ymin) < radius_squared) ? 1 : 0;
1841
/* top right test */
1842
else if (cent[1] > bucket_bounds->ymax) {
1843
return (Vec2Lenf_nosqrt_other(cent, bucket_bounds->xmax, bucket_bounds->ymax) < radius_squared) ? 1 : 0;
1852
/* Note for rect_to_uvspace_ortho() and rect_to_uvspace_persp()
1853
* in ortho view this function gives good results when bucket_bounds are outside the triangle
1854
* however in some cases, perspective view will mess up with faces that have minimal screenspace area (viewed from the side)
1856
* for this reason its not relyable in this case so we'll use the Simple Barycentric' funcs that only account for points inside the triangle.
1857
* however switching back to this for ortho is always an option */
1859
static void rect_to_uvspace_ortho(
1860
rctf *bucket_bounds,
1861
float *v1coSS, float *v2coSS, float *v3coSS,
1862
float *uv1co, float *uv2co, float *uv3co,
1863
float bucket_bounds_uv[4][2],
1869
/* get the UV space bounding box */
1870
uv[0] = bucket_bounds->xmax;
1871
uv[1] = bucket_bounds->ymin;
1872
BarycentricWeights2f(uv, v1coSS, v2coSS, v3coSS, w);
1873
Vec2Weightf(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w);
1875
//uv[0] = bucket_bounds->xmax; // set above
1876
uv[1] = bucket_bounds->ymax;
1877
BarycentricWeights2f(uv, v1coSS, v2coSS, v3coSS, w);
1878
Vec2Weightf(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w);
1880
uv[0] = bucket_bounds->xmin;
1881
//uv[1] = bucket_bounds->ymax; // set above
1882
BarycentricWeights2f(uv, v1coSS, v2coSS, v3coSS, w);
1883
Vec2Weightf(bucket_bounds_uv[flip?1:2], uv1co, uv2co, uv3co, w);
1885
//uv[0] = bucket_bounds->xmin; // set above
1886
uv[1] = bucket_bounds->ymin;
1887
BarycentricWeights2f(uv, v1coSS, v2coSS, v3coSS, w);
1888
Vec2Weightf(bucket_bounds_uv[flip?0:3], uv1co, uv2co, uv3co, w);
1891
/* same as above but use BarycentricWeightsPersp2f */
1892
static void rect_to_uvspace_persp(
1893
rctf *bucket_bounds,
1894
float *v1coSS, float *v2coSS, float *v3coSS,
1895
float *uv1co, float *uv2co, float *uv3co,
1896
float bucket_bounds_uv[4][2],
1903
/* get the UV space bounding box */
1904
uv[0] = bucket_bounds->xmax;
1905
uv[1] = bucket_bounds->ymin;
1906
BarycentricWeightsPersp2f(uv, v1coSS, v2coSS, v3coSS, w);
1907
Vec2Weightf(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w);
1909
//uv[0] = bucket_bounds->xmax; // set above
1910
uv[1] = bucket_bounds->ymax;
1911
BarycentricWeightsPersp2f(uv, v1coSS, v2coSS, v3coSS, w);
1912
Vec2Weightf(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w);
1914
uv[0] = bucket_bounds->xmin;
1915
//uv[1] = bucket_bounds->ymax; // set above
1916
BarycentricWeightsPersp2f(uv, v1coSS, v2coSS, v3coSS, w);
1917
Vec2Weightf(bucket_bounds_uv[flip?1:2], uv1co, uv2co, uv3co, w);
1919
//uv[0] = bucket_bounds->xmin; // set above
1920
uv[1] = bucket_bounds->ymin;
1921
BarycentricWeightsPersp2f(uv, v1coSS, v2coSS, v3coSS, w);
1922
Vec2Weightf(bucket_bounds_uv[flip?0:3], uv1co, uv2co, uv3co, w);
1925
/* This works as we need it to but we can save a few steps and not use it */
1927
static float angle_2d_clockwise(const float p1[2], const float p2[2], const float p3[2])
1931
v1[0] = p1[0]-p2[0]; v1[1] = p1[1]-p2[1];
1932
v2[0] = p3[0]-p2[0]; v2[1] = p3[1]-p2[1];
1934
return -atan2(v1[0]*v2[1] - v1[1]*v2[0], v1[0]*v2[0]+v1[1]*v2[1]);
1939
#define ISECT_2 (1<<1)
1940
#define ISECT_3 (1<<2)
1941
#define ISECT_4 (1<<3)
1942
#define ISECT_ALL3 ((1<<3)-1)
1943
#define ISECT_ALL4 ((1<<4)-1)
1945
/* limit must be a fraction over 1.0f */
1946
static int IsectPT2Df_limit(float pt[2], float v1[2], float v2[2], float v3[2], float limit)
1948
return ((AreaF2Dfl(pt,v1,v2) + AreaF2Dfl(pt,v2,v3) + AreaF2Dfl(pt,v3,v1)) / (AreaF2Dfl(v1,v2,v3))) < limit;
1951
/* Clip the face by a bucket and set the uv-space bucket_bounds_uv
1952
* so we have the clipped UV's to do pixel intersection tests with
1954
static int float_z_sort_flip(const void *p1, const void *p2) {
1955
return (((float *)p1)[2] < ((float *)p2)[2] ? 1:-1);
1958
static int float_z_sort(const void *p1, const void *p2) {
1959
return (((float *)p1)[2] < ((float *)p2)[2] ?-1:1);
1962
static void project_bucket_clip_face(
1964
rctf *bucket_bounds,
1965
float *v1coSS, float *v2coSS, float *v3coSS,
1966
float *uv1co, float *uv2co, float *uv3co,
1967
float bucket_bounds_uv[8][2],
1970
int inside_bucket_flag = 0;
1971
int inside_face_flag = 0;
1972
const int flip = ((SIDE_OF_LINE(v1coSS, v2coSS, v3coSS) > 0.0f) != (SIDE_OF_LINE(uv1co, uv2co, uv3co) > 0.0f));
1974
float bucket_bounds_ss[4][2];
1976
/* get the UV space bounding box */
1977
inside_bucket_flag |= BLI_in_rctf(bucket_bounds, v1coSS[0], v1coSS[1]);
1978
inside_bucket_flag |= BLI_in_rctf(bucket_bounds, v2coSS[0], v2coSS[1]) << 1;
1979
inside_bucket_flag |= BLI_in_rctf(bucket_bounds, v3coSS[0], v3coSS[1]) << 2;
1981
if (inside_bucket_flag == ISECT_ALL3) {
1982
/* all screenspace points are inside the bucket bounding box, this means we dont need to clip and can simply return the UVs */
1983
if (flip) { /* facing the back? */
1984
VECCOPY2D(bucket_bounds_uv[0], uv3co);
1985
VECCOPY2D(bucket_bounds_uv[1], uv2co);
1986
VECCOPY2D(bucket_bounds_uv[2], uv1co);
1989
VECCOPY2D(bucket_bounds_uv[0], uv1co);
1990
VECCOPY2D(bucket_bounds_uv[1], uv2co);
1991
VECCOPY2D(bucket_bounds_uv[2], uv3co);
1998
/* get the UV space bounding box */
1999
/* use IsectPT2Df_limit here so we catch points are are touching the tri edge (or a small fraction over) */
2000
bucket_bounds_ss[0][0] = bucket_bounds->xmax;
2001
bucket_bounds_ss[0][1] = bucket_bounds->ymin;
2002
inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[0], v1coSS, v2coSS, v3coSS, 1+PROJ_GEOM_TOLERANCE) ? ISECT_1 : 0);
2004
bucket_bounds_ss[1][0] = bucket_bounds->xmax;
2005
bucket_bounds_ss[1][1] = bucket_bounds->ymax;
2006
inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[1], v1coSS, v2coSS, v3coSS, 1+PROJ_GEOM_TOLERANCE) ? ISECT_2 : 0);
2008
bucket_bounds_ss[2][0] = bucket_bounds->xmin;
2009
bucket_bounds_ss[2][1] = bucket_bounds->ymax;
2010
inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[2], v1coSS, v2coSS, v3coSS, 1+PROJ_GEOM_TOLERANCE) ? ISECT_3 : 0);
2012
bucket_bounds_ss[3][0] = bucket_bounds->xmin;
2013
bucket_bounds_ss[3][1] = bucket_bounds->ymin;
2014
inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[3], v1coSS, v2coSS, v3coSS, 1+PROJ_GEOM_TOLERANCE) ? ISECT_4 : 0);
2016
if (inside_face_flag == ISECT_ALL4) {
2017
/* bucket is totally inside the screenspace face, we can safely use weights */
2019
if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
2020
else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
2026
/* The Complicated Case!
2028
* The 2 cases above are where the face is inside the bucket or the bucket is inside the face.
2030
* we need to make a convex polyline from the intersection between the screenspace face
2031
* and the bucket bounds.
2033
* There are a number of ways this could be done, currently it just collects all intersecting verts,
2034
* and line intersections, then sorts them clockwise, this is a lot easier then evaluating the geometry to
2035
* do a correct clipping on both shapes. */
2038
/* add a bunch of points, we know must make up the convex hull which is the clipped rect and triangle */
2042
/* Maximum possible 6 intersections when using a rectangle and triangle */
2043
float isectVCosSS[8][3]; /* The 3rd float is used to store angle for qsort(), NOT as a Z location */
2044
float v1_clipSS[2], v2_clipSS[2];
2048
float cent[2] = {0.0f, 0.0f};
2049
/*float up[2] = {0.0f, 1.0f};*/
2055
if (inside_face_flag & ISECT_1) { VECCOPY2D(isectVCosSS[*tot], bucket_bounds_ss[0]); (*tot)++; }
2056
if (inside_face_flag & ISECT_2) { VECCOPY2D(isectVCosSS[*tot], bucket_bounds_ss[1]); (*tot)++; }
2057
if (inside_face_flag & ISECT_3) { VECCOPY2D(isectVCosSS[*tot], bucket_bounds_ss[2]); (*tot)++; }
2058
if (inside_face_flag & ISECT_4) { VECCOPY2D(isectVCosSS[*tot], bucket_bounds_ss[3]); (*tot)++; }
2060
if (inside_bucket_flag & ISECT_1) { VECCOPY2D(isectVCosSS[*tot], v1coSS); (*tot)++; }
2061
if (inside_bucket_flag & ISECT_2) { VECCOPY2D(isectVCosSS[*tot], v2coSS); (*tot)++; }
2062
if (inside_bucket_flag & ISECT_3) { VECCOPY2D(isectVCosSS[*tot], v3coSS); (*tot)++; }
2064
if ((inside_bucket_flag & (ISECT_1|ISECT_2)) != (ISECT_1|ISECT_2)) {
2065
if (line_clip_rect2f(bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
2066
if ((inside_bucket_flag & ISECT_1)==0) { VECCOPY2D(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
2067
if ((inside_bucket_flag & ISECT_2)==0) { VECCOPY2D(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
2071
if ((inside_bucket_flag & (ISECT_2|ISECT_3)) != (ISECT_2|ISECT_3)) {
2072
if (line_clip_rect2f(bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
2073
if ((inside_bucket_flag & ISECT_2)==0) { VECCOPY2D(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
2074
if ((inside_bucket_flag & ISECT_3)==0) { VECCOPY2D(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
2078
if ((inside_bucket_flag & (ISECT_3|ISECT_1)) != (ISECT_3|ISECT_1)) {
2079
if (line_clip_rect2f(bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
2080
if ((inside_bucket_flag & ISECT_3)==0) { VECCOPY2D(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
2081
if ((inside_bucket_flag & ISECT_1)==0) { VECCOPY2D(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
2086
if ((*tot) < 3) { /* no intersections to speak of */
2091
/* now we have all points we need, collect their angles and sort them clockwise */
2093
for(i=0; i<(*tot); i++) {
2094
cent[0] += isectVCosSS[i][0];
2095
cent[1] += isectVCosSS[i][1];
2097
cent[0] = cent[0] / (float)(*tot);
2098
cent[1] = cent[1] / (float)(*tot);
2102
/* Collect angles for every point around the center point */
2105
#if 0 /* uses a few more cycles then the above loop */
2106
for(i=0; i<(*tot); i++) {
2107
isectVCosSS[i][2] = angle_2d_clockwise(up, cent, isectVCosSS[i]);
2111
v1_clipSS[0] = cent[0]; /* Abuse this var for the loop below */
2112
v1_clipSS[1] = cent[1] + 1.0f;
2114
for(i=0; i<(*tot); i++) {
2115
v2_clipSS[0] = isectVCosSS[i][0] - cent[0];
2116
v2_clipSS[1] = isectVCosSS[i][1] - cent[1];
2117
isectVCosSS[i][2] = atan2f(v1_clipSS[0]*v2_clipSS[1] - v1_clipSS[1]*v2_clipSS[0], v1_clipSS[0]*v2_clipSS[0]+v1_clipSS[1]*v2_clipSS[1]);
2120
if (flip) qsort(isectVCosSS, *tot, sizeof(float)*3, float_z_sort_flip);
2121
else qsort(isectVCosSS, *tot, sizeof(float)*3, float_z_sort);
2123
/* remove doubles */
2124
/* first/last check */
2125
if (fabsf(isectVCosSS[0][0]-isectVCosSS[(*tot)-1][0]) < PROJ_GEOM_TOLERANCE && fabsf(isectVCosSS[0][1]-isectVCosSS[(*tot)-1][1]) < PROJ_GEOM_TOLERANCE) {
2129
/* its possible there is only a few left after remove doubles */
2131
// printf("removed too many doubles A\n");
2137
while (doubles==TRUE) {
2139
for(i=1; i<(*tot); i++) {
2140
if (fabsf(isectVCosSS[i-1][0]-isectVCosSS[i][0]) < PROJ_GEOM_TOLERANCE &&
2141
fabsf(isectVCosSS[i-1][1]-isectVCosSS[i][1]) < PROJ_GEOM_TOLERANCE)
2144
for(j=i+1; j<(*tot); j++) {
2145
isectVCosSS[j-1][0] = isectVCosSS[j][0];
2146
isectVCosSS[j-1][1] = isectVCosSS[j][1];
2148
doubles = TRUE; /* keep looking for more doubles */
2154
/* its possible there is only a few left after remove doubles */
2156
// printf("removed too many doubles B\n");
2163
for(i=0; i<(*tot); i++) {
2164
BarycentricWeights2f(isectVCosSS[i], v1coSS, v2coSS, v3coSS, w);
2165
Vec2Weightf(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
2169
for(i=0; i<(*tot); i++) {
2170
BarycentricWeightsPersp2f(isectVCosSS[i], v1coSS, v2coSS, v3coSS, w);
2171
Vec2Weightf(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
2176
#ifdef PROJ_DEBUG_PRINT_CLIP
2177
/* include this at the bottom of the above function to debug the output */
2180
/* If there are ever any problems, */
2181
float test_uv[4][2];
2183
if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
2184
else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
2185
printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ", test_uv[0][0], test_uv[0][1], test_uv[1][0], test_uv[1][1], test_uv[2][0], test_uv[2][1], test_uv[3][0], test_uv[3][1]);
2187
printf(" [(%f,%f), (%f,%f), (%f,%f)], ", uv1co[0], uv1co[1], uv2co[0], uv2co[1], uv3co[0], uv3co[1]);
2190
for (i=0; i < (*tot); i++) {
2191
printf("(%f, %f),", bucket_bounds_uv[i][0], bucket_bounds_uv[i][1]);
2199
# This script creates faces in a blender scene from printed data above.
2202
...(output from above block)...
2205
from Blender import Scene, Mesh, Window, sys, Mathutils
2209
V = Mathutils.Vector
2212
sce = bpy.data.scenes.active
2214
for item in project_ls:
2219
me = bpy.data.meshes.new()
2220
ob = sce.objects.new(me)
2222
me.verts.extend([V(bb[0]).resize3D(), V(bb[1]).resize3D(), V(bb[2]).resize3D(), V(bb[3]).resize3D()])
2223
me.faces.extend([(0,1,2,3),])
2224
me.verts.extend([V(uv[0]).resize3D(), V(uv[1]).resize3D(), V(uv[2]).resize3D()])
2225
me.faces.extend([(4,5,6),])
2227
vs = [V(p).resize3D() for p in poly]
2233
while i < len(me.verts):
2235
if ii==len(me.verts):
2237
me.edges.extend([i, ii])
2240
if __name__ == '__main__':
2253
/* checks if pt is inside a convex 2D polyline, the polyline must be ordered rotating clockwise
2254
* otherwise it would have to test for mixed (SIDE_OF_LINE > 0.0f) cases */
2255
int IsectPoly2Df(const float pt[2], float uv[][2], const int tot)
2258
if (SIDE_OF_LINE(uv[tot-1], uv[0], pt) < 0.0f)
2261
for (i=1; i<tot; i++) {
2262
if (SIDE_OF_LINE(uv[i-1], uv[i], pt) < 0.0f)
2269
static int IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot)
2272
int side = (SIDE_OF_LINE(uv[tot-1], uv[0], pt) > 0.0f);
2274
for (i=1; i<tot; i++) {
2275
if ((SIDE_OF_LINE(uv[i-1], uv[i], pt) > 0.0f) != side)
2283
/* One of the most important function for projectiopn painting, since it selects the pixels to be added into each bucket.
2284
* initialize pixels from this face where it intersects with the bucket_index, optionally initialize pixels for removing seams */
2285
static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, const ImBuf *ibuf)
2287
/* Projection vars, to get the 3D locations into screen space */
2288
MemArena *arena = ps->arena_mt[thread_index];
2289
LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index;
2290
LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index];
2292
const MFace *mf = ps->dm_mface + face_index;
2293
const MTFace *tf = ps->dm_mtface + face_index;
2295
/* UV/pixel seeking data */
2296
int x; /* Image X-Pixel */
2297
int y;/* Image Y-Pixel */
2299
float uv[2]; /* Image floating point UV - same as x, y but from 0.0-1.0 */
2302
float *v1coSS, *v2coSS, *v3coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
2304
float *vCo[4]; /* vertex screenspace coords */
2308
float *uv1co, *uv2co, *uv3co; /* for convenience only, these will be assigned to tf->uv[0],1,2 or tf->uv[0],2,3 */
2309
float pixelScreenCo[4];
2311
rcti bounds_px; /* ispace bounds */
2312
/* vars for getting uvspace bounds */
2314
float tf_uv_pxoffset[4][2]; /* bucket bounds in UV space so we can init pixels only for this face, */
2315
float xhalfpx, yhalfpx;
2316
const float ibuf_xf = ibuf->x, ibuf_yf = ibuf->y;
2318
int has_x_isect = 0, has_isect = 0; /* for early loop exit */
2322
float uv_clip[8][2];
2324
const short is_ortho = ps->is_ortho;
2325
const short do_backfacecull = ps->do_backfacecull;
2327
vCo[0] = ps->dm_mvert[mf->v1].co;
2328
vCo[1] = ps->dm_mvert[mf->v2].co;
2329
vCo[2] = ps->dm_mvert[mf->v3].co;
2332
/* Use tf_uv_pxoffset instead of tf->uv so we can offset the UV half a pixel
2333
* this is done so we can avoid offseting all the pixels by 0.5 which causes
2334
* problems when wrapping negative coords */
2335
xhalfpx = (0.5f+ (PROJ_GEOM_TOLERANCE/3.0f) ) / ibuf_xf;
2336
yhalfpx = (0.5f+ (PROJ_GEOM_TOLERANCE/4.0f) ) / ibuf_yf;
2338
/* Note about (PROJ_GEOM_TOLERANCE/x) above...
2339
Needed to add this offset since UV coords are often quads aligned to pixels.
2340
In this case pixels can be exactly between 2 triangles causing nasty
2343
This workaround can be removed and painting will still work on most cases
2344
but since the first thing most people try is painting onto a quad- better make it work.
2349
tf_uv_pxoffset[0][0] = tf->uv[0][0] - xhalfpx;
2350
tf_uv_pxoffset[0][1] = tf->uv[0][1] - yhalfpx;
2352
tf_uv_pxoffset[1][0] = tf->uv[1][0] - xhalfpx;
2353
tf_uv_pxoffset[1][1] = tf->uv[1][1] - yhalfpx;
2355
tf_uv_pxoffset[2][0] = tf->uv[2][0] - xhalfpx;
2356
tf_uv_pxoffset[2][1] = tf->uv[2][1] - yhalfpx;
2359
vCo[3] = ps->dm_mvert[ mf->v4 ].co;
2361
tf_uv_pxoffset[3][0] = tf->uv[3][0] - xhalfpx;
2362
tf_uv_pxoffset[3][1] = tf->uv[3][1] - yhalfpx;
2377
uv1co = tf_uv_pxoffset[i1]; // was tf->uv[i1];
2378
uv2co = tf_uv_pxoffset[i2]; // was tf->uv[i2];
2379
uv3co = tf_uv_pxoffset[i3]; // was tf->uv[i3];
2381
v1coSS = ps->screenCoords[ (*(&mf->v1 + i1)) ];
2382
v2coSS = ps->screenCoords[ (*(&mf->v1 + i2)) ];
2383
v3coSS = ps->screenCoords[ (*(&mf->v1 + i3)) ];
2385
/* This funtion gives is a concave polyline in UV space from the clipped quad and tri*/
2386
project_bucket_clip_face(
2387
is_ortho, bucket_bounds,
2388
v1coSS, v2coSS, v3coSS,
2389
uv1co, uv2co, uv3co,
2390
uv_clip, &uv_clip_tot
2393
/* sometimes this happens, better just allow for 8 intersectiosn even though there should be max 6 */
2395
if (uv_clip_tot>6) {
2396
printf("this should never happen! %d\n", uv_clip_tot);
2400
if (pixel_bounds_array(uv_clip, &bounds_px, ibuf->x, ibuf->y, uv_clip_tot)) {
2405
for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
2406
//uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
2407
uv[1] = (float)y / ibuf_yf; /* use pixel offset UV coords instead */
2410
for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
2411
//uv[0] = (((float)x) + 0.5f) / ibuf->x;
2412
uv[0] = (float)x / ibuf_xf; /* use pixel offset UV coords instead */
2414
/* Note about IsectPoly2Df_twoside, checking the face or uv flipping doesnt work,
2415
* could check the poly direction but better to do this */
2416
if( (do_backfacecull && IsectPoly2Df(uv, uv_clip, uv_clip_tot)) ||
2417
(do_backfacecull==0 && IsectPoly2Df_twoside(uv, uv_clip, uv_clip_tot))) {
2419
has_x_isect = has_isect = 1;
2421
if (is_ortho) screen_px_from_ortho(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
2422
else screen_px_from_persp(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
2424
/* a pitty we need to get the worldspace pixel location here */
2425
if(G.vd->flag & V3D_CLIPPING) {
2426
VecWeightf(wco, ps->dm_mvert[ (*(&mf->v1 + i1)) ].co, ps->dm_mvert[ (*(&mf->v1 + i2)) ].co, ps->dm_mvert[ (*(&mf->v1 + i3)) ].co, w);
2427
Mat4MulVecfl(ps->ob->obmat, wco);
2428
if(view3d_test_clipping(G.vd, wco)) {
2429
continue; /* Watch out that no code below this needs to run */
2433
/* Is this UV visible from the view? - raytrace */
2434
/* project_paint_PickFace is less complex, use for testing */
2435
//if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == face_index) {
2436
if (ps->do_occlude==0 || !project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo)) {
2438
mask = project_paint_uvpixel_mask(ps, face_index, side, w);
2441
BLI_linklist_prepend_arena(
2443
project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, side, w),
2451
else if (has_x_isect) {
2452
/* assuming the face is not a bow-tie - we know we cant intersect again on the X */
2459
#if 0 /* TODO - investigate why this dosnt work sometimes! it should! */
2460
/* no intersection for this entire row, after some intersection above means we can quit now */
2461
if (has_x_isect==0 && has_isect) {
2471
#ifndef PROJ_DEBUG_NOSEAMBLEED
2472
if (ps->seam_bleed_px > 0.0f) {
2475
if (ps->thread_tot > 1)
2476
BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
2478
face_seam_flag = ps->faceSeamFlags[face_index];
2480
/* are any of our edges un-initialized? */
2481
if ((face_seam_flag & (PROJ_FACE_SEAM1|PROJ_FACE_NOSEAM1))==0 ||
2482
(face_seam_flag & (PROJ_FACE_SEAM2|PROJ_FACE_NOSEAM2))==0 ||
2483
(face_seam_flag & (PROJ_FACE_SEAM3|PROJ_FACE_NOSEAM3))==0 ||
2484
(face_seam_flag & (PROJ_FACE_SEAM4|PROJ_FACE_NOSEAM4))==0
2486
project_face_seams_init(ps, face_index, mf->v4);
2487
face_seam_flag = ps->faceSeamFlags[face_index];
2488
//printf("seams - %d %d %d %d\n", flag&PROJ_FACE_SEAM1, flag&PROJ_FACE_SEAM2, flag&PROJ_FACE_SEAM3, flag&PROJ_FACE_SEAM4);
2491
if ((face_seam_flag & (PROJ_FACE_SEAM1|PROJ_FACE_SEAM2|PROJ_FACE_SEAM3|PROJ_FACE_SEAM4))==0) {
2493
if (ps->thread_tot > 1)
2494
BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
2498
/* we have a seam - deal with it! */
2500
/* Now create new UV's for the seam face */
2501
float (*outset_uv)[2] = ps->faceSeamUVs[face_index];
2502
float insetCos[4][3]; /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in prespective view */
2505
float *vCoSS[4]; /* vertex screenspace coords */
2507
float bucket_clip_edges[2][2]; /* store the screenspace coords of the face, clipped by the bucket's screen aligned rectangle */
2508
float edge_verts_inset_clip[2][3];
2509
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 */
2511
float seam_subsection[4][2];
2512
float fac1, fac2, ftot;
2515
if (outset_uv[0][0]==MAXFLOAT) /* first time initialize */
2516
uv_image_outset(tf_uv_pxoffset, outset_uv, ps->seam_bleed_px, ibuf->x, ibuf->y, mf->v4);
2518
/* ps->faceSeamUVs cant be modified when threading, now this is done we can unlock */
2519
if (ps->thread_tot > 1)
2520
BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
2522
vCoSS[0] = ps->screenCoords[mf->v1];
2523
vCoSS[1] = ps->screenCoords[mf->v2];
2524
vCoSS[2] = ps->screenCoords[mf->v3];
2526
vCoSS[3] = ps->screenCoords[ mf->v4 ];
2528
/* PROJ_FACE_SCALE_SEAM must be slightly less then 1.0f */
2530
if (mf->v4) scale_quad(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM);
2531
else scale_tri(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM);
2534
if (mf->v4) scale_quad(insetCos, vCo, PROJ_FACE_SCALE_SEAM);
2535
else scale_tri(insetCos, vCo, PROJ_FACE_SCALE_SEAM);
2538
side = 0; /* for triangles this wont need to change */
2540
for (fidx1 = 0; fidx1 < (mf->v4 ? 4 : 3); fidx1++) {
2541
if (mf->v4) fidx2 = (fidx1==3) ? 0 : fidx1+1; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) */
2542
else fidx2 = (fidx1==2) ? 0 : fidx1+1; /* next fidx in the face (0,1,2) -> (1,2,0) */
2544
if ( (face_seam_flag & (1<<fidx1)) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */
2545
line_clip_rect2f(bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1])
2548
ftot = Vec2Lenf(vCoSS[fidx1], vCoSS[fidx2]); /* screenspace edge length */
2550
if (ftot > 0.0f) { /* avoid div by zero */
2552
if (fidx1==2 || fidx2==2) side= 1;
2556
fac1 = Vec2Lenf(vCoSS[fidx1], bucket_clip_edges[0]) / ftot;
2557
fac2 = Vec2Lenf(vCoSS[fidx1], bucket_clip_edges[1]) / ftot;
2559
Vec2Lerpf(seam_subsection[0], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac1);
2560
Vec2Lerpf(seam_subsection[1], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac2);
2562
Vec2Lerpf(seam_subsection[2], outset_uv[fidx1], outset_uv[fidx2], fac2);
2563
Vec2Lerpf(seam_subsection[3], outset_uv[fidx1], outset_uv[fidx2], fac1);
2565
/* if the bucket_clip_edges values Z values was kept we could avoid this
2566
* Inset needs to be added so occlusion tests wont hit adjacent faces */
2567
VecLerpf(edge_verts_inset_clip[0], insetCos[fidx1], insetCos[fidx2], fac1);
2568
VecLerpf(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2);
2571
if (pixel_bounds_uv(seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3], &bounds_px, ibuf->x, ibuf->y, 1)) {
2572
/* bounds between the seam rect and the uvspace bucket pixels */
2575
for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
2576
// uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
2577
uv[1] = (float)y / ibuf_yf; /* use offset uvs instead */
2580
for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
2581
//uv[0] = (((float)x) + 0.5f) / (float)ibuf->x;
2582
uv[0] = (float)x / ibuf_xf; /* use offset uvs instead */
2584
/* test we're inside uvspace bucket and triangle bounds */
2585
if (IsectPQ2Df(uv, seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3])) {
2587
/* We need to find the closest point along the face edge,
2588
* getting the screen_px_from_*** wont work because our actual location
2589
* is not relevent, since we are outside the face, Use VecLerpf to find
2590
* our location on the side of the face's UV */
2592
if (is_ortho) screen_px_from_ortho(ps, uv, v1co, v2co, v3co, uv1co, uv2co, uv3co, pixelScreenCo);
2593
else screen_px_from_persp(ps, uv, v1co, v2co, v3co, uv1co, uv2co, uv3co, pixelScreenCo);
2596
/* Since this is a seam we need to work out where on the line this pixel is */
2597
//fac = lambda_cp_line2(uv, uv_seam_quad[0], uv_seam_quad[1]);
2599
fac = lambda_cp_line2(uv, seam_subsection[0], seam_subsection[1]);
2600
if (fac < 0.0f) { VECCOPY(pixelScreenCo, edge_verts_inset_clip[0]); }
2601
else if (fac > 1.0f) { VECCOPY(pixelScreenCo, edge_verts_inset_clip[1]); }
2602
else { VecLerpf(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac); }
2605
pixelScreenCo[3] = 1.0f;
2606
Mat4MulVec4fl((float (*)[4])*ps->projectMat, pixelScreenCo);
2607
pixelScreenCo[0] = (float)(curarea->winx/2.0f)+(curarea->winx/2.0f)*pixelScreenCo[0]/pixelScreenCo[3];
2608
pixelScreenCo[1] = (float)(curarea->winy/2.0f)+(curarea->winy/2.0f)*pixelScreenCo[1]/pixelScreenCo[3];
2609
pixelScreenCo[2] = pixelScreenCo[2]/pixelScreenCo[3]; /* Use the depth for bucket point occlusion */
2612
if (ps->do_occlude==0 || !project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo)) {
2614
/* Only bother calculating the weights if we intersect */
2615
if (ps->do_mask_normal || ps->dm_mtface_clone) {
2617
/* This is not QUITE correct since UV is not inside the UV's but good enough for seams */
2619
BarycentricWeights2f(uv, tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], w);
2622
BarycentricWeights2f(uv, tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], w);
2626
/* Cheat, we know where we are along the edge so work out the weights from that */
2627
fac = fac1 + (fac * (fac2-fac1));
2628
w[0]=w[1]=w[2]= 0.0;
2630
w[fidx1?fidx1-1:0] = fac;
2631
w[fidx2?fidx2-1:0] = 1.0-fac;
2640
/* a pitty we need to get the worldspace pixel location here */
2641
if(G.vd->flag & V3D_CLIPPING) {
2642
if (side) VecWeightf(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
2643
else VecWeightf(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
2645
Mat4MulVecfl(ps->ob->obmat, wco);
2646
if(view3d_test_clipping(G.vd, wco)) {
2647
continue; /* Watch out that no code below this needs to run */
2651
mask = project_paint_uvpixel_mask(ps, face_index, side, w);
2654
BLI_linklist_prepend_arena(
2656
project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, side, w),
2663
else if (has_x_isect) {
2664
/* assuming the face is not a bow-tie - we know we cant intersect again on the X */
2669
#if 0 /* TODO - investigate why this dosnt work sometimes! it should! */
2670
/* no intersection for this entire row, after some intersection above means we can quit now */
2671
if (has_x_isect==0 && has_isect) {
2682
#endif // PROJ_DEBUG_NOSEAMBLEED
2686
/* takes floating point screenspace min/max and returns int min/max to be used as indicies for ps->bucketRect, ps->bucketFlags */
2687
static void project_paint_bucket_bounds(const ProjPaintState *ps, const float min[2], const float max[2], int bucketMin[2], int bucketMax[2])
2689
/* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */
2690
bucketMin[0] = (int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f; /* these offsets of 0.5 and 1.5 seem odd but they are correct */
2691
bucketMin[1] = (int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 0.5f;
2693
bucketMax[0] = (int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f;
2694
bucketMax[1] = (int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 1.5f;
2696
/* incase the rect is outside the mesh 2d bounds */
2697
CLAMP(bucketMin[0], 0, ps->buckets_x);
2698
CLAMP(bucketMin[1], 0, ps->buckets_y);
2700
CLAMP(bucketMax[0], 0, ps->buckets_x);
2701
CLAMP(bucketMax[1], 0, ps->buckets_y);
2704
/* set bucket_bounds to a screen space-aligned floating point bound-box */
2705
static void project_bucket_bounds(const ProjPaintState *ps, const int bucket_x, const int bucket_y, rctf *bucket_bounds)
2707
bucket_bounds->xmin = ps->screenMin[0]+((bucket_x)*(ps->screen_width / ps->buckets_x)); /* left */
2708
bucket_bounds->xmax = ps->screenMin[0]+((bucket_x+1)*(ps->screen_width / ps->buckets_x)); /* right */
2710
bucket_bounds->ymin = ps->screenMin[1]+((bucket_y)*(ps->screen_height / ps->buckets_y)); /* bottom */
2711
bucket_bounds->ymax = ps->screenMin[1]+((bucket_y+1)*(ps->screen_height / ps->buckets_y)); /* top */
2714
/* Fill this bucket with pixels from the faces that intersect it.
2716
* have bucket_bounds as an argument so we don;t need to give bucket_x/y the rect function needs */
2717
static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, rctf *bucket_bounds)
2720
int face_index, image_index;
2724
Image *tpage_last = NULL;
2727
if (ps->image_tot==1) {
2728
/* Simple loop, no context switching */
2729
ibuf = ps->projImages[0].ibuf;
2731
for (node = ps->bucketFaces[bucket_index]; node; node= node->next) {
2732
project_paint_face_init(ps, thread_index, bucket_index, (int)node->link, 0, bucket_bounds, ibuf);
2737
/* More complicated loop, switch between images */
2738
for (node = ps->bucketFaces[bucket_index]; node; node= node->next) {
2739
face_index = (int)node->link;
2741
/* Image context switching */
2742
tf = ps->dm_mtface+face_index;
2743
if (tpage_last != tf->tpage) {
2744
tpage_last = tf->tpage;
2746
image_index = -1; /* sanity check */
2748
for (image_index=0; image_index < ps->image_tot; image_index++) {
2749
if (ps->projImages[image_index].ima == tpage_last) {
2750
ibuf = ps->projImages[image_index].ibuf;
2755
/* context switching done */
2757
project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf);
2762
ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT;
2766
/* We want to know if a bucket and a face overlap in screen-space
2768
* Note, if this ever returns false positives its not that bad, since a face in the bounding area will have its pixels
2769
* calculated when it might not be needed later, (at the moment at least)
2770
* obviously it shouldn't have bugs though */
2772
static int project_bucket_face_isect(ProjPaintState *ps, float min[2], float max[2], int bucket_x, int bucket_y, int bucket_index, const MFace *mf)
2774
/* TODO - replace this with a tricker method that uses sideofline for all screenCoords's edges against the closest bucket corner */
2776
float p1[2], p2[2], p3[2], p4[2];
2777
float *v, *v1,*v2,*v3,*v4;
2780
project_bucket_bounds(ps, bucket_x, bucket_y, &bucket_bounds);
2782
/* Is one of the faces verts in the bucket bounds? */
2784
fidx = mf->v4 ? 3:2;
2786
v = ps->screenCoords[ (*(&mf->v1 + fidx)) ];
2787
if (BLI_in_rctf(&bucket_bounds, v[0], v[1])) {
2792
v1 = ps->screenCoords[mf->v1];
2793
v2 = ps->screenCoords[mf->v2];
2794
v3 = ps->screenCoords[mf->v3];
2796
v4 = ps->screenCoords[mf->v4];
2799
p1[0] = bucket_bounds.xmin; p1[1] = bucket_bounds.ymin;
2800
p2[0] = bucket_bounds.xmin; p2[1] = bucket_bounds.ymax;
2801
p3[0] = bucket_bounds.xmax; p3[1] = bucket_bounds.ymax;
2802
p4[0] = bucket_bounds.xmax; p4[1] = bucket_bounds.ymin;
2805
if( IsectPQ2Df(p1, v1, v2, v3, v4) || IsectPQ2Df(p2, v1, v2, v3, v4) || IsectPQ2Df(p3, v1, v2, v3, v4) || IsectPQ2Df(p4, v1, v2, v3, v4) ||
2806
/* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
2807
(IsectLL2Df(p1, p2, v1, v2) || IsectLL2Df(p1, p2, v2, v3) || IsectLL2Df(p1, p2, v3, v4)) ||
2808
(IsectLL2Df(p2, p3, v1, v2) || IsectLL2Df(p2, p3, v2, v3) || IsectLL2Df(p2, p3, v3, v4)) ||
2809
(IsectLL2Df(p3, p4, v1, v2) || IsectLL2Df(p3, p4, v2, v3) || IsectLL2Df(p3, p4, v3, v4)) ||
2810
(IsectLL2Df(p4, p1, v1, v2) || IsectLL2Df(p4, p1, v2, v3) || IsectLL2Df(p4, p1, v3, v4))
2816
if( IsectPT2Df(p1, v1, v2, v3) || IsectPT2Df(p2, v1, v2, v3) || IsectPT2Df(p3, v1, v2, v3) || IsectPT2Df(p4, v1, v2, v3) ||
2817
/* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
2818
(IsectLL2Df(p1, p2, v1, v2) || IsectLL2Df(p1, p2, v2, v3)) ||
2819
(IsectLL2Df(p2, p3, v1, v2) || IsectLL2Df(p2, p3, v2, v3)) ||
2820
(IsectLL2Df(p3, p4, v1, v2) || IsectLL2Df(p3, p4, v2, v3)) ||
2821
(IsectLL2Df(p4, p1, v1, v2) || IsectLL2Df(p4, p1, v2, v3))
2830
/* Add faces to the bucket but dont initialize its pixels
2831
* TODO - when painting occluded, sort the faces on their min-Z and only add faces that faces that are not occluded */
2832
static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf, const MTFace *tf, const int face_index)
2834
float min[2], max[2], *vCoSS;
2835
int bucketMin[2], bucketMax[2]; /* for ps->bucketRect indexing */
2836
int fidx, bucket_x, bucket_y, bucket_index;
2837
int has_x_isect = -1, has_isect = 0; /* for early loop exit */
2838
MemArena *arena = ps->arena_mt[0]; /* just use the first thread arena since threading has not started yet */
2840
INIT_MINMAX2(min, max);
2842
fidx = mf->v4 ? 3:2;
2844
vCoSS = ps->screenCoords[ *(&mf->v1 + fidx) ];
2845
DO_MINMAX2(vCoSS, min, max);
2848
project_paint_bucket_bounds(ps, min, max, bucketMin, bucketMax);
2850
for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) {
2852
for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x++) {
2854
bucket_index = bucket_x + (bucket_y * ps->buckets_x);
2856
if (project_bucket_face_isect(ps, min, max, bucket_x, bucket_y, bucket_index, mf)) {
2857
BLI_linklist_prepend_arena(
2858
&ps->bucketFaces[ bucket_index ],
2859
SET_INT_IN_POINTER(face_index), /* cast to a pointer to shut up the compiler */
2863
has_x_isect = has_isect = 1;
2865
else if (has_x_isect) {
2866
/* assuming the face is not a bow-tie - we know we cant intersect again on the X */
2871
/* no intersection for this entire row, after some intersection above means we can quit now */
2872
if (has_x_isect==0 && has_isect) {
2877
#ifndef PROJ_DEBUG_NOSEAMBLEED
2878
if (ps->seam_bleed_px > 0.0f) {
2880
ps->faceSeamFlags[face_index] |= PROJ_FACE_NOSEAM4; /* so this wont show up as an untagged edge */
2882
**ps->faceSeamUVs[face_index] = MAXFLOAT; /* set as uninitialized */
2887
/* run once per stroke before projection painting */
2888
static void project_paint_begin(ProjPaintState *ps, short mval[2])
2895
float (*projScreenCo)[4]; /* Note, we could have 4D vectors are only needed for */
2897
/* Image Vars - keep track of images we have used */
2898
LinkNode *image_LinkList = NULL;
2901
ProjPaintImage *projIma;
2902
Image *tpage_last = NULL;
2908
int a, i; /* generic looping vars */
2909
int image_index = -1, face_index;
2911
MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */
2913
/* ---- end defines ---- */
2915
/* paint onto the derived mesh */
2916
ps->dm = mesh_get_derived_final(ps->ob, get_viewedit_datamask());
2918
if ( !CustomData_has_layer( &ps->dm->faceData, CD_MTFACE) ) {
2922
ps->dm_mvert = ps->dm->getVertArray(ps->dm);
2923
ps->dm_mface = ps->dm->getFaceArray(ps->dm);
2924
ps->dm_mtface= ps->dm->getFaceDataArray(ps->dm, CD_MTFACE);
2926
ps->dm_totvert = ps->dm->getNumVerts(ps->dm);
2927
ps->dm_totface = ps->dm->getNumFaces(ps->dm);
2929
/* use clone mtface? */
2932
/* Note, use the original mesh for getting the clone and mask layer index
2933
* this avoids re-generating the derived mesh just to get the new index */
2934
if (ps->do_layer_clone) {
2935
//int layer_num = CustomData_get_clone_layer(&ps->dm->faceData, CD_MTFACE);
2936
int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE);
2937
if (layer_num != -1)
2938
ps->dm_mtface_clone = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
2940
if (ps->dm_mtface_clone==NULL || ps->dm_mtface_clone==ps->dm_mtface) {
2941
ps->do_layer_clone = 0;
2942
ps->dm_mtface_clone= NULL;
2946
if (ps->do_layer_mask) {
2947
//int layer_num = CustomData_get_mask_layer(&ps->dm->faceData, CD_MTFACE);
2948
int layer_num = CustomData_get_mask_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE);
2949
if (layer_num != -1)
2950
ps->dm_mtface_mask = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
2952
if (ps->dm_mtface_mask==NULL || ps->dm_mtface_mask==ps->dm_mtface) {
2953
ps->do_layer_mask = 0;
2954
ps->dm_mtface_mask = NULL;
2960
ps->viewDir[0] = 0.0f;
2961
ps->viewDir[1] = 0.0f;
2962
ps->viewDir[2] = 1.0f;
2964
view3d_get_object_project_mat(curarea, ps->ob, ps->projectMat, ps->viewMat);
2966
/* viewDir - object relative */
2967
Mat4Invert(ps->ob->imat, ps->ob->obmat);
2968
Mat3CpyMat4(mat, G.vd->viewinv);
2969
Mat3MulVecfl(mat, ps->viewDir);
2970
Mat3CpyMat4(mat, ps->ob->imat);
2971
Mat3MulVecfl(mat, ps->viewDir);
2972
Normalize(ps->viewDir);
2974
/* viewPos - object relative */
2975
VECCOPY(ps->viewPos, G.vd->viewinv[3]);
2976
Mat3CpyMat4(mat, ps->ob->imat);
2977
Mat3MulVecfl(mat, ps->viewPos);
2978
VecAddf(ps->viewPos, ps->viewPos, ps->ob->imat[3]);
2980
{ /* only use these for running 'get_view3d_viewplane' */
2983
ps->is_ortho = get_view3d_viewplane(curarea->winx, curarea->winy, &viewplane, &ps->clipsta, &ps->clipend, NULL);
2985
//printf("%f %f\n", ps->clipsta, ps->clipend);
2986
if (ps->is_ortho) { /* only needed for ortho */
2987
float fac = 2.0f / (ps->clipend - ps->clipsta);
2992
/* TODO - can we even adjust for clip start/end? */
2997
ps->is_airbrush = (ps->brush->flag & BRUSH_AIRBRUSH) ? 1 : 0;
2999
ps->is_texbrush = (ps->brush->mtex[ps->brush->texact] && ps->brush->mtex[ps->brush->texact]->tex) ? 1 : 0;
3002
/* calculate vert screen coords
3003
* run this early so we can calculate the x/y resolution of our bucket rect */
3004
INIT_MINMAX2(ps->screenMin, ps->screenMax);
3006
ps->screenCoords = MEM_mallocN(sizeof(float) * ps->dm_totvert * 4, "ProjectPaint ScreenVerts");
3007
projScreenCo = ps->screenCoords;
3010
for(a=0; a < ps->dm_totvert; a++, projScreenCo++) {
3011
VECCOPY((*projScreenCo), ps->dm_mvert[a].co);
3012
Mat4MulVecfl(ps->projectMat, (*projScreenCo));
3014
/* screen space, not clamped */
3015
(*projScreenCo)[0] = (float)(curarea->winx/2.0f)+(curarea->winx/2.0f)*(*projScreenCo)[0];
3016
(*projScreenCo)[1] = (float)(curarea->winy/2.0f)+(curarea->winy/2.0f)*(*projScreenCo)[1];
3017
DO_MINMAX2((*projScreenCo), ps->screenMin, ps->screenMax);
3021
for(a=0; a < ps->dm_totvert; a++, projScreenCo++) {
3022
VECCOPY((*projScreenCo), ps->dm_mvert[a].co);
3023
(*projScreenCo)[3] = 1.0f;
3025
Mat4MulVec4fl(ps->projectMat, (*projScreenCo));
3028
if ((*projScreenCo)[3] > ps->clipsta) {
3029
/* screen space, not clamped */
3030
(*projScreenCo)[0] = (float)(curarea->winx/2.0f)+(curarea->winx/2.0f)*(*projScreenCo)[0]/(*projScreenCo)[3];
3031
(*projScreenCo)[1] = (float)(curarea->winy/2.0f)+(curarea->winy/2.0f)*(*projScreenCo)[1]/(*projScreenCo)[3];
3032
(*projScreenCo)[2] = (*projScreenCo)[2]/(*projScreenCo)[3]; /* Use the depth for bucket point occlusion */
3033
DO_MINMAX2((*projScreenCo), ps->screenMin, ps->screenMax);
3036
/* TODO - deal with cases where 1 side of a face goes behind the view ?
3038
* After some research this is actually very tricky, only option is to
3039
* clip the derived mesh before painting, which is a Pain */
3040
(*projScreenCo)[0] = MAXFLOAT;
3045
/* If this border is not added we get artifacts for faces that
3046
* have a parallel edge and at the bounds of the the 2D projected verts eg
3047
* - a single screen aligned quad */
3048
projMargin = (ps->screenMax[0] - ps->screenMin[0]) * 0.000001f;
3049
ps->screenMax[0] += projMargin;
3050
ps->screenMin[0] -= projMargin;
3051
projMargin = (ps->screenMax[1] - ps->screenMin[1]) * 0.000001f;
3052
ps->screenMax[1] += projMargin;
3053
ps->screenMin[1] -= projMargin;
3055
#ifdef PROJ_DEBUG_WINCLIP
3056
CLAMP(ps->screenMin[0], -ps->brush->size, curarea->winx + ps->brush->size);
3057
CLAMP(ps->screenMax[0], -ps->brush->size, curarea->winx + ps->brush->size);
3059
CLAMP(ps->screenMin[1], -ps->brush->size, curarea->winy + ps->brush->size);
3060
CLAMP(ps->screenMax[1], -ps->brush->size, curarea->winy + ps->brush->size);
3063
/* only for convenience */
3064
ps->screen_width = ps->screenMax[0] - ps->screenMin[0];
3065
ps->screen_height = ps->screenMax[1] - ps->screenMin[1];
3067
ps->buckets_x = (int)(ps->screen_width / (((float)ps->brush->size) / PROJ_BUCKET_BRUSH_DIV));
3068
ps->buckets_y = (int)(ps->screen_height / (((float)ps->brush->size) / PROJ_BUCKET_BRUSH_DIV));
3070
/* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */
3072
/* really high values could cause problems since it has to allocate a few
3073
* (ps->buckets_x*ps->buckets_y) sized arrays */
3074
CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
3075
CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
3077
ps->bucketRect = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketRect");
3078
ps->bucketFaces= (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
3080
ps->bucketFlags= (unsigned char *)MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
3081
#ifndef PROJ_DEBUG_NOSEAMBLEED
3082
if (ps->seam_bleed_px > 0.0f) {
3083
ps->vertFaces= (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->dm_totvert, "paint-vertFaces");
3084
ps->faceSeamFlags = (char *)MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceSeamFlags");
3085
ps->faceSeamUVs= MEM_mallocN(sizeof(float) * ps->dm_totface * 8, "paint-faceSeamUVs");
3091
* very small brushes run a lot slower multithreaded since the advantage with
3092
* threads is being able to fill in multiple buckets at once.
3093
* Only use threads for bigger brushes. */
3095
if (G.scene->r.mode & R_FIXED_THREADS) {
3096
ps->thread_tot = G.scene->r.threads;
3099
ps->thread_tot = BLI_system_thread_count();
3101
for (a=0; a<ps->thread_tot; a++) {
3102
ps->arena_mt[a] = BLI_memarena_new(1<<16);
3105
arena = ps->arena_mt[0];
3107
if (ps->do_backfacecull && ps->do_mask_normal) {
3108
MVert *v = ps->dm_mvert;
3109
float viewDirPersp[3];
3111
ps->vertFlags = MEM_callocN(sizeof(char) * ps->dm_totvert, "paint-vertFlags");
3113
for(a=0; a < ps->dm_totvert; a++, v++) {
3114
no[0] = (float)(v->no[0] / 32767.0f);
3115
no[1] = (float)(v->no[1] / 32767.0f);
3116
no[2] = (float)(v->no[2] / 32767.0f);
3119
if (NormalizedVecAngle2(ps->viewDir, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
3120
ps->vertFlags[a] |= PROJ_VERT_CULL;
3124
VecSubf(viewDirPersp, ps->viewPos, v->co);
3125
Normalize(viewDirPersp);
3126
if (NormalizedVecAngle2(viewDirPersp, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
3127
ps->vertFlags[a] |= PROJ_VERT_CULL;
3133
/* setup clone offset */
3134
if (ps->tool == PAINT_TOOL_CLONE) {
3136
float *curs= give_cursor();
3137
VECCOPY(projCo, curs);
3138
Mat4MulVecfl(ps->ob->imat, projCo);
3141
Mat4MulVec4fl(ps->projectMat, projCo);
3142
ps->cloneOffset[0] = mval[0] - ((float)(curarea->winx/2.0f)+(curarea->winx/2.0f)*projCo[0]/projCo[3]);
3143
ps->cloneOffset[1] = mval[1] - ((float)(curarea->winy/2.0f)+(curarea->winy/2.0f)*projCo[1]/projCo[3]);
3145
// printf("%f %f %f %f %f\n", ps->cloneOffset[0], ps->cloneOffset[1], curs[0], curs[1], curs[2]);
3151
for(face_index = 0, tf = ps->dm_mtface, mf = ps->dm_mface; face_index < ps->dm_totface; mf++, tf++, face_index++) {
3153
#ifndef PROJ_DEBUG_NOSEAMBLEED
3154
/* add face user if we have bleed enabled, set the UV seam flags later */
3155
/* annoying but we need to add all faces even ones we never use elsewhere */
3156
if (ps->seam_bleed_px > 0.0f) {
3157
BLI_linklist_prepend_arena(&ps->vertFaces[mf->v1], (void *)face_index, arena);
3158
BLI_linklist_prepend_arena(&ps->vertFaces[mf->v2], (void *)face_index, arena);
3159
BLI_linklist_prepend_arena(&ps->vertFaces[mf->v3], (void *)face_index, arena);
3161
BLI_linklist_prepend_arena(&ps->vertFaces[ mf->v4 ], (void *)face_index, arena);
3166
if (tf->tpage && ((G.f & G_FACESELECT)==0 || mf->flag & ME_FACE_SEL)) {
3168
float *v1coSS, *v2coSS, *v3coSS, *v4coSS;
3170
v1coSS = ps->screenCoords[mf->v1];
3171
v2coSS = ps->screenCoords[mf->v2];
3172
v3coSS = ps->screenCoords[mf->v3];
3174
v4coSS = ps->screenCoords[mf->v4];
3178
if (!ps->is_ortho) {
3179
if ( v1coSS[0]==MAXFLOAT ||
3180
v2coSS[0]==MAXFLOAT ||
3181
v3coSS[0]==MAXFLOAT ||
3182
(mf->v4 && v4coSS[0]==MAXFLOAT)
3188
#ifdef PROJ_DEBUG_WINCLIP
3189
/* ignore faces outside the view */
3191
(v1coSS[0] < ps->screenMin[0] &&
3192
v2coSS[0] < ps->screenMin[0] &&
3193
v3coSS[0] < ps->screenMin[0] &&
3194
(mf->v4 && v4coSS[0] < ps->screenMin[0])) ||
3196
(v1coSS[0] > ps->screenMax[0] &&
3197
v2coSS[0] > ps->screenMax[0] &&
3198
v3coSS[0] > ps->screenMax[0] &&
3199
(mf->v4 && v4coSS[0] > ps->screenMax[0])) ||
3201
(v1coSS[1] < ps->screenMin[1] &&
3202
v2coSS[1] < ps->screenMin[1] &&
3203
v3coSS[1] < ps->screenMin[1] &&
3204
(mf->v4 && v4coSS[1] < ps->screenMin[1])) ||
3206
(v1coSS[1] > ps->screenMax[1] &&
3207
v2coSS[1] > ps->screenMax[1] &&
3208
v3coSS[1] > ps->screenMax[1] &&
3209
(mf->v4 && v4coSS[1] > ps->screenMax[1]))
3214
#endif //PROJ_DEBUG_WINCLIP
3217
if (ps->do_backfacecull) {
3218
if (ps->do_mask_normal) {
3219
/* Since we are interpolating the normals of faces, we want to make
3220
* sure all the verts are pointing away from the view,
3221
* not just the face */
3222
if ( (ps->vertFlags[mf->v1] & PROJ_VERT_CULL) &&
3223
(ps->vertFlags[mf->v2] & PROJ_VERT_CULL) &&
3224
(ps->vertFlags[mf->v3] & PROJ_VERT_CULL) &&
3225
(mf->v4==0 || ps->vertFlags[mf->v4] & PROJ_VERT_CULL)
3232
if (SIDE_OF_LINE(v1coSS, v2coSS, v3coSS) < 0.0f) {
3239
if (tpage_last != tf->tpage) {
3241
image_index = BLI_linklist_index(image_LinkList, tf->tpage);
3243
if (image_index==-1 && BKE_image_get_ibuf(tf->tpage, NULL)) { /* MemArena dosnt have an append func */
3244
BLI_linklist_append(&image_LinkList, tf->tpage);
3245
image_index = ps->image_tot;
3249
tpage_last = tf->tpage;
3252
if (image_index != -1) {
3253
/* Initialize the faces screen pixels */
3254
/* Add this to a list to initialize later */
3255
project_paint_delayed_face_init(ps, mf, tf, face_index);
3260
/* build an array of images we use*/
3261
projIma = ps->projImages = (ProjPaintImage *)BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot);
3263
for (node= image_LinkList, i=0; node; node= node->next, i++, projIma++) {
3264
projIma->ima = node->link;
3266
projIma->ibuf = BKE_image_get_ibuf(projIma->ima, NULL);
3267
projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
3268
memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
3271
/* we have built the array, discard the linked list */
3272
BLI_linklist_free(image_LinkList, NULL);
3275
static void project_paint_end(ProjPaintState *ps)
3279
/* build undo data from original pixel colors */
3280
if(U.uiflag & USER_GLOBALUNDO) {
3281
ProjPixel *projPixel;
3282
ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL;
3283
LinkNode *pixel_node;
3285
MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for non threaded case */
3287
int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could get an X/Y but easier to loop through all possible buckets */
3290
int x_round, y_round;
3295
ProjPaintImage *last_projIma;
3296
int last_image_index = -1;
3297
int last_tile_width;
3299
for(a=0, last_projIma=ps->projImages; a < ps->image_tot; a++, last_projIma++) {
3300
int size = sizeof(UndoTile **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y);
3301
last_projIma->undoRect = (UndoTile **) BLI_memarena_alloc(arena, size);
3302
memset(last_projIma->undoRect, 0, size);
3303
last_projIma->ibuf->userflags |= IB_BITMAPDIRTY;
3306
for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) {
3307
/* loop through all pixels */
3308
for(pixel_node= ps->bucketRect[bucket_index]; pixel_node; pixel_node= pixel_node->next) {
3310
/* ok we have a pixel, was it modified? */
3311
projPixel = (ProjPixel *)pixel_node->link;
3313
if (last_image_index != projPixel->image_index) {
3314
/* set the context */
3315
last_image_index = projPixel->image_index;
3316
last_projIma = ps->projImages + last_image_index;
3317
last_tile_width = IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x);
3318
is_float = last_projIma->ibuf->rect_float ? 1 : 0;
3322
if ( (is_float == 0 && projPixel->origColor.uint != *projPixel->pixel.uint_pt) ||
3325
( projPixel->origColor.f[0] != projPixel->pixel.f_pt[0] ||
3326
projPixel->origColor.f[1] != projPixel->pixel.f_pt[1] ||
3327
projPixel->origColor.f[2] != projPixel->pixel.f_pt[2] ||
3328
projPixel->origColor.f[3] != projPixel->pixel.f_pt[3] ))
3331
x_tile = projPixel->x_px >> IMAPAINT_TILE_BITS;
3332
y_tile = projPixel->y_px >> IMAPAINT_TILE_BITS;
3334
x_round = x_tile * IMAPAINT_TILE_SIZE;
3335
y_round = y_tile * IMAPAINT_TILE_SIZE;
3337
tile_index = x_tile + y_tile * last_tile_width;
3339
if (last_projIma->undoRect[tile_index]==NULL) {
3340
/* add the undo tile from the modified image, then write the original colors back into it */
3341
tile = last_projIma->undoRect[tile_index] = undo_init_tile(&last_projIma->ima->id, last_projIma->ibuf, is_float ? (&tmpibuf_float):(&tmpibuf) , x_tile, y_tile);
3344
tile = last_projIma->undoRect[tile_index];
3347
/* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color
3348
* because allocating the tiles allong the way slows down painting */
3351
float *rgba_fp = (float *)tile->rect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4;
3352
QUATCOPY(rgba_fp, projPixel->origColor.f);
3355
((unsigned int *)tile->rect)[ (projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE ] = projPixel->origColor.uint;
3361
if (tmpibuf) IMB_freeImBuf(tmpibuf);
3362
if (tmpibuf_float) IMB_freeImBuf(tmpibuf_float);
3364
/* done calculating undo data */
3366
MEM_freeN(ps->screenCoords);
3367
MEM_freeN(ps->bucketRect);
3368
MEM_freeN(ps->bucketFaces);
3369
MEM_freeN(ps->bucketFlags);
3371
#ifndef PROJ_DEBUG_NOSEAMBLEED
3372
if (ps->seam_bleed_px > 0.0f) {
3373
MEM_freeN(ps->vertFaces);
3374
MEM_freeN(ps->faceSeamFlags);
3375
MEM_freeN(ps->faceSeamUVs);
3379
if (ps->vertFlags) MEM_freeN(ps->vertFlags);
3381
for (a=0; a<ps->thread_tot; a++) {
3382
BLI_memarena_free(ps->arena_mt[a]);
3385
ps->dm->release(ps->dm);
3388
/* Use this rather then mouse_cursor()
3389
* so rotating the view leaves the 3D Cursor on the clone source surface.
3391
static void project_paint_setCursor(void) {
3392
float *curs = give_cursor();
3395
mouse_cursor(); /* set the cursor location on the view X/Y */
3396
getmouseco_areawin(mval);
3397
view_mouse_depth(curs, mval, 1);
286
3400
/* 1= an undo, -1 is a redo. */
3401
static void partial_redraw_array_init(ImagePaintPartialRedraw *pr)
3403
int tot = PROJ_BOUNDBOX_SQUARED;
3418
static int partial_redraw_array_merge(ImagePaintPartialRedraw *pr, ImagePaintPartialRedraw *pr_other, int tot)
3422
pr->x1 = MIN2(pr->x1, pr_other->x1);
3423
pr->y1 = MIN2(pr->y1, pr_other->y1);
3425
pr->x2 = MAX2(pr->x2, pr_other->x2);
3426
pr->y2 = MAX2(pr->y2, pr_other->y2);
3437
/* Loop over all images on this mesh and update any we have touched */
3438
static int project_image_refresh_tagged(ProjPaintState *ps)
3440
ImagePaintPartialRedraw *pr;
3441
ProjPaintImage *projIma;
3446
for (a=0, projIma=ps->projImages; a < ps->image_tot; a++, projIma++) {
3447
if (projIma->touch) {
3448
/* look over each bound cell */
3449
for (i=0; i<PROJ_BOUNDBOX_SQUARED; i++) {
3450
pr = &(projIma->partRedrawRect[i]);
3451
if (pr->x2 != -1) { /* TODO - use 'enabled' ? */
3452
imapaintpartial = *pr;
3453
imapaint_image_update(projIma->ima, projIma->ibuf, 1); /*last 1 is for texpaint*/
3458
projIma->touch = 0; /* clear for reuse */
3465
/* run this per painting onto each mouse location */
3466
static int project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2])
3468
float min_brush[2], max_brush[2];
3469
float size_half = ((float)ps->brush->size) * 0.5f;
3471
/* so we dont have a bucket bounds that is way too small to paint into */
3472
// if (size_half < 1.0f) size_half = 1.0f; // this dosnt work yet :/
3474
min_brush[0] = mval_f[0] - size_half;
3475
min_brush[1] = mval_f[1] - size_half;
3477
max_brush[0] = mval_f[0] + size_half;
3478
max_brush[1] = mval_f[1] + size_half;
3480
/* offset to make this a valid bucket index */
3481
project_paint_bucket_bounds(ps, min_brush, max_brush, ps->bucketMin, ps->bucketMax);
3483
/* mouse outside the model areas? */
3484
if (ps->bucketMin[0]==ps->bucketMax[0] || ps->bucketMin[1]==ps->bucketMax[1]) {
3488
ps->context_bucket_x = ps->bucketMin[0];
3489
ps->context_bucket_y = ps->bucketMin[1];
3493
static int project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf *bucket_bounds, const float mval[2])
3495
if (ps->thread_tot > 1)
3496
BLI_lock_thread(LOCK_CUSTOM1);
3498
//printf("%d %d \n", ps->context_bucket_x, ps->context_bucket_y);
3500
for ( ; ps->context_bucket_y < ps->bucketMax[1]; ps->context_bucket_y++) {
3501
for ( ; ps->context_bucket_x < ps->bucketMax[0]; ps->context_bucket_x++) {
3503
/* use bucket_bounds for project_bucket_isect_circle and project_bucket_init*/
3504
project_bucket_bounds(ps, ps->context_bucket_x, ps->context_bucket_y, bucket_bounds);
3506
if (project_bucket_isect_circle(ps->context_bucket_x, ps->context_bucket_y, mval, ps->brush->size * ps->brush->size, bucket_bounds)) {
3507
*bucket_index = ps->context_bucket_x + (ps->context_bucket_y * ps->buckets_x);
3508
ps->context_bucket_x++;
3510
if (ps->thread_tot > 1)
3511
BLI_unlock_thread(LOCK_CUSTOM1);
3516
ps->context_bucket_x = ps->bucketMin[0];
3519
if (ps->thread_tot > 1)
3520
BLI_unlock_thread(LOCK_CUSTOM1);
3524
/* Each thread gets one of these, also used as an argument to pass to project_paint_op */
3525
typedef struct ProjectHandle {
3531
/* annoying but we need to have image bounds per thread, then merge into ps->projectPartialRedraws */
3532
ProjPaintImage *projImages; /* array of partial redraws */
3534
/* thread settings */
3538
static void blend_color_mix(unsigned char *cp, const unsigned char *cp1, const unsigned char *cp2, const int fac)
3540
/* this and other blending modes previously used >>8 instead of /255. both
3541
are not equivalent (>>8 is /256), and the former results in rounding
3542
errors that can turn colors black fast after repeated blending */
3543
const int mfac= 255-fac;
3545
cp[0]= (mfac*cp1[0]+fac*cp2[0])/255;
3546
cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
3547
cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
3548
cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
3551
static void blend_color_mix_float(float *cp, const float *cp1, const float *cp2, const float fac)
3553
const float mfac= 1.0-fac;
3554
cp[0]= mfac*cp1[0] + fac*cp2[0];
3555
cp[1]= mfac*cp1[1] + fac*cp2[1];
3556
cp[2]= mfac*cp1[2] + fac*cp2[2];
3557
cp[3]= mfac*cp1[3] + fac*cp2[3];
3560
static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask)
3562
if (ps->is_airbrush==0 && mask < 1.0f) {
3563
projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, ((ProjPixelClone*)projPixel)->clonepx.uint, (int)(alpha*255), ps->blend);
3564
blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask*255));
3567
*projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.uint_pt, ((ProjPixelClone*)projPixel)->clonepx.uint, (int)(alpha*mask*255), ps->blend);
3571
static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask)
3573
if (ps->is_airbrush==0 && mask < 1.0f) {
3574
IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, ((ProjPixelClone *)projPixel)->clonepx.f, alpha, ps->blend);
3575
blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask);
3578
IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f, alpha*mask, ps->blend);
3582
/* do_projectpaint_smear*
3584
* note, mask is used to modify the alpha here, this is not correct since it allows
3585
* accumulation of color greater then 'projPixel->mask' however in the case of smear its not
3586
* really that important to be correct as it is with clone and painting
3588
static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels, float co[2])
3590
unsigned char rgba_ub[4];
3592
if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1)==0)
3594
/* ((ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */
3595
blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha*mask*255));
3596
BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena);
3599
static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels_f, float co[2])
3601
unsigned char rgba_ub[4];
3602
unsigned char rgba_smear[4];
3604
if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1)==0)
3607
IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba_smear, projPixel->pixel.f_pt);
3608
/* (ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*((unsigned int *)rgba_smear), *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */
3609
blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, rgba_smear, (rgba_ub), (int)(alpha*mask*255));
3610
BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena);
3613
static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask)
3615
unsigned char rgba_ub[4];
3617
if (ps->is_texbrush) {
3618
rgba_ub[0] = FTOCHAR(rgba[0] * ps->brush->rgb[0]);
3619
rgba_ub[1] = FTOCHAR(rgba[1] * ps->brush->rgb[1]);
3620
rgba_ub[2] = FTOCHAR(rgba[2] * ps->brush->rgb[2]);
3621
rgba_ub[3] = FTOCHAR(rgba[3]);
3624
IMAPAINT_FLOAT_RGB_TO_CHAR(rgba_ub, ps->brush->rgb);
3628
if (ps->is_airbrush==0 && mask < 1.0f) {
3629
projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, *((unsigned int *)rgba_ub), (int)(alpha*255), ps->blend);
3630
blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask*255));
3633
*projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend);
3637
static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask) {
3638
if (ps->is_texbrush) {
3639
rgba[0] *= ps->brush->rgb[0];
3640
rgba[1] *= ps->brush->rgb[1];
3641
rgba[2] *= ps->brush->rgb[2];
3644
VECCOPY(rgba, ps->brush->rgb);
3647
if (ps->is_airbrush==0 && mask < 1.0f) {
3648
IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, rgba, alpha, ps->blend);
3649
blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask);
3652
IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, alpha*mask, ps->blend);
3658
/* run this for single and multithreaded painting */
3659
static void *do_projectpaint_thread(void *ph_v)
3661
/* First unpack args from the struct */
3662
ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps;
3663
ProjPaintImage *projImages = ((ProjectHandle *)ph_v)->projImages;
3664
const float *lastpos = ((ProjectHandle *)ph_v)->prevmval;
3665
const float *pos = ((ProjectHandle *)ph_v)->mval;
3666
const int thread_index = ((ProjectHandle *)ph_v)->thread_index;
3667
/* Done with args from ProjectHandle */
3670
ProjPixel *projPixel;
3672
int last_index = -1;
3673
ProjPaintImage *last_projIma;
3674
ImagePaintPartialRedraw *last_partial_redraw_cell;
3676
float rgba[4], alpha, dist_nosqrt;
3678
float brush_size_sqared;
3681
int is_floatbuf = 0;
3682
const short tool = ps->tool;
3685
/* for smear only */
3688
float mask = 1.0f; /* airbrush wont use mask */
3689
unsigned short mask_short;
3691
LinkNode *smearPixels = NULL;
3692
LinkNode *smearPixels_f = NULL;
3693
MemArena *smearArena = NULL; /* mem arena for this brush projection only */
3696
if (tool==PAINT_TOOL_SMEAR) {
3697
pos_ofs[0] = pos[0] - lastpos[0];
3698
pos_ofs[1] = pos[1] - lastpos[1];
3700
smearArena = BLI_memarena_new(1<<16);
3703
/* avoid a square root with every dist comparison */
3704
brush_size_sqared = ps->brush->size * ps->brush->size;
3706
/* printf("brush bounds %d %d %d %d\n", bucketMin[0], bucketMin[1], bucketMax[0], bucketMax[1]); */
3708
while (project_bucket_iter_next(ps, &bucket_index, &bucket_bounds, pos)) {
3710
/* Check this bucket and its faces are initialized */
3711
if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
3712
/* No pixels initialized */
3713
project_bucket_init(ps, thread_index, bucket_index, &bucket_bounds);
3716
for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
3718
projPixel = (ProjPixel *)node->link;
3720
/*dist = Vec2Lenf(projPixel->projCoSS, pos);*/ /* correct but uses a sqrtf */
3721
dist_nosqrt = Vec2Lenf_nosqrt(projPixel->projCoSS, pos);
3723
/*if (dist < s->brush->size) {*/ /* correct but uses a sqrtf */
3724
if (dist_nosqrt < brush_size_sqared) {
3725
falloff = brush_sample_falloff_noalpha(ps->brush, sqrtf(dist_nosqrt));
3726
if (falloff > 0.0f) {
3727
if (ps->is_texbrush) {
3728
brush_sample_tex(ps->brush, projPixel->projCoSS, rgba);
3734
if (ps->is_airbrush) {
3735
/* for an aurbrush there is no real mask, so just multiply the alpha by it */
3736
alpha *= falloff * ps->brush->alpha;
3737
mask = ((float)projPixel->mask)/65535.0f;
3740
/* This brush dosnt accumulate so add some curve to the brushes falloff */
3741
falloff = 1.0f - falloff;
3742
falloff = 1.0f - (falloff * falloff);
3744
mask_short = projPixel->mask * (ps->brush->alpha * falloff);
3745
if (mask_short > projPixel->mask_max) {
3746
mask = ((float)mask_short)/65535.0f;
3747
projPixel->mask_max = mask_short;
3750
/*mask = ((float)projPixel->mask_max)/65535.0f;*/
3752
/* Go onto the next pixel */
3759
if (last_index != projPixel->image_index) {
3760
last_index = projPixel->image_index;
3761
last_projIma = projImages + last_index;
3763
last_projIma->touch = 1;
3764
is_floatbuf = last_projIma->ibuf->rect_float ? 1 : 0;
3767
last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
3768
last_partial_redraw_cell->x1 = MIN2(last_partial_redraw_cell->x1, projPixel->x_px);
3769
last_partial_redraw_cell->y1 = MIN2(last_partial_redraw_cell->y1, projPixel->y_px);
3771
last_partial_redraw_cell->x2 = MAX2(last_partial_redraw_cell->x2, projPixel->x_px+1);
3772
last_partial_redraw_cell->y2 = MAX2(last_partial_redraw_cell->y2, projPixel->y_px+1);
3776
case PAINT_TOOL_CLONE:
3778
if (((ProjPixelClone *)projPixel)->clonepx.f[3]) {
3779
do_projectpaint_clone_f(ps, projPixel, rgba, alpha, mask);
3783
if (((ProjPixelClone*)projPixel)->clonepx.ch[3]) {
3784
do_projectpaint_clone(ps, projPixel, rgba, alpha, mask);
3788
case PAINT_TOOL_SMEAR:
3789
Vec2Subf(co, projPixel->projCoSS, pos_ofs);
3791
if (is_floatbuf) do_projectpaint_smear_f(ps, projPixel, rgba, alpha, mask, smearArena, &smearPixels_f, co);
3792
else do_projectpaint_smear(ps, projPixel, rgba, alpha, mask, smearArena, &smearPixels, co);
3795
if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, rgba, alpha, mask);
3796
else do_projectpaint_draw(ps, projPixel, rgba, alpha, mask);
3807
if (tool==PAINT_TOOL_SMEAR) {
3809
for (node= smearPixels; node; node= node->next) { /* this wont run for a float image */
3810
projPixel = node->link;
3811
*projPixel->pixel.uint_pt = ((ProjPixelClone *)projPixel)->clonepx.uint;
3814
for (node= smearPixels_f; node; node= node->next) {
3815
projPixel = node->link;
3816
IMAPAINT_CHAR_RGBA_TO_FLOAT(projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.ch);
3819
BLI_memarena_free(smearArena);
3825
static int project_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *pos)
3827
/* First unpack args from the struct */
3828
ProjPaintState *ps = (ProjPaintState *)state;
3831
ProjectHandle handles[BLENDER_MAX_THREADS];
3835
if (!project_bucket_iter_init(ps, pos)) {
3839
if (ps->thread_tot > 1)
3840
BLI_init_threads(&threads, do_projectpaint_thread, ps->thread_tot);
3842
/* get the threads running */
3843
for(a=0; a < ps->thread_tot; a++) {
3845
/* set defaults in handles */
3846
//memset(&handles[a], 0, sizeof(BakeShade));
3849
VECCOPY2D(handles[a].mval, pos);
3850
VECCOPY2D(handles[a].prevmval, lastpos);
3852
/* thread spesific */
3853
handles[a].thread_index = a;
3855
handles[a].projImages = (ProjPaintImage *)BLI_memarena_alloc(ps->arena_mt[a], ps->image_tot * sizeof(ProjPaintImage));
3857
memcpy(handles[a].projImages, ps->projImages, ps->image_tot * sizeof(ProjPaintImage));
3860
for (i=0; i< ps->image_tot; i++) {
3861
handles[a].projImages[i].partRedrawRect = (ImagePaintPartialRedraw *)BLI_memarena_alloc(ps->arena_mt[a], sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
3862
memcpy(handles[a].projImages[i].partRedrawRect, ps->projImages[i].partRedrawRect, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
3865
if (ps->thread_tot > 1)
3866
BLI_insert_thread(&threads, &handles[a]);
3869
if (ps->thread_tot > 1) /* wait for everything to be done */
3870
BLI_end_threads(&threads);
3872
do_projectpaint_thread(&handles[0]);
3875
/* move threaded bounds back into ps->projectPartialRedraws */
3876
for(i=0; i < ps->image_tot; i++) {
3878
for(a=0; a < ps->thread_tot; a++) {
3879
touch |= partial_redraw_array_merge(ps->projImages[i].partRedrawRect, handles[a].projImages[i].partRedrawRect, PROJ_BOUNDBOX_SQUARED);
3883
ps->projImages[i].touch = 1;
3892
static int project_paint_sub_stroke(ProjPaintState *ps, BrushPainter *painter, short *prevmval_i, short *mval_i, double time, float pressure)
3895
/* Use mouse coords as floats for projection painting */
3901
// we may want to use this later
3902
// brush_painter_require_imbuf(painter, ((ibuf->rect_float)? 1: 0), 0, 0);
3904
if (brush_painter_paint(painter, project_paint_op, pos, time, pressure, ps)) {
3911
static int project_paint_stroke(ProjPaintState *ps, BrushPainter *painter, short *prevmval_i, short *mval_i, double time, int update, float pressure)
3915
for (a=0; a < ps->image_tot; a++) {
3916
partial_redraw_array_init(ps->projImages[a].partRedrawRect);
3919
redraw |= project_paint_sub_stroke(ps, painter, prevmval_i, mval_i, time, pressure);
3922
if (project_image_refresh_tagged(ps)) {
3924
force_draw(0); /* imapaint_redraw just calls this in viewport paint anyway */
3925
/* imapaint_redraw(0, 1, NULL); */
3926
/* imapaint_clear_partial_redraw(); */ /* not needed since we use our own array */
287
3934
void undo_imagepaint_step(int step)