diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/blenkernel/intern/mask_rasterize.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/blenkernel/intern/mask_rasterize.c')
-rw-r--r-- | source/blender/blenkernel/intern/mask_rasterize.c | 2355 |
1 files changed, 1185 insertions, 1170 deletions
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index a1405f1243c..24137b680ba 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -91,51 +91,55 @@ #define BUCKET_PIXELS_PER_CELL 4 #define SF_EDGE_IS_BOUNDARY 0xff -#define SF_KEYINDEX_TEMP_ID ((unsigned int) -1) +#define SF_KEYINDEX_TEMP_ID ((unsigned int)-1) -#define TRI_TERMINATOR_ID ((unsigned int) -1) -#define TRI_VERT ((unsigned int) -1) +#define TRI_TERMINATOR_ID ((unsigned int)-1) +#define TRI_VERT ((unsigned int)-1) /* for debugging add... */ #ifndef NDEBUG /* printf("%u %u %u %u\n", _t[0], _t[1], _t[2], _t[3]); \ */ -# define FACE_ASSERT(face, vert_max) \ -{ \ - unsigned int *_t = face; \ - BLI_assert(_t[0] < vert_max); \ - BLI_assert(_t[1] < vert_max); \ - BLI_assert(_t[2] < vert_max); \ - BLI_assert(_t[3] < vert_max || _t[3] == TRI_VERT); \ -} (void)0 +# define FACE_ASSERT(face, vert_max) \ + { \ + unsigned int *_t = face; \ + BLI_assert(_t[0] < vert_max); \ + BLI_assert(_t[1] < vert_max); \ + BLI_assert(_t[2] < vert_max); \ + BLI_assert(_t[3] < vert_max || _t[3] == TRI_VERT); \ + } \ + (void)0 #else - /* do nothing */ +/* do nothing */ # define FACE_ASSERT(face, vert_max) #endif static CLG_LogRef LOG = {"bke.mask_rasterize"}; -static void rotate_point_v2(float r_p[2], const float p[2], const float cent[2], const float angle, const float asp[2]) +static void rotate_point_v2( + float r_p[2], const float p[2], const float cent[2], const float angle, const float asp[2]) { - const float s = sinf(angle); - const float c = cosf(angle); - float p_new[2]; + const float s = sinf(angle); + const float c = cosf(angle); + float p_new[2]; - /* translate point back to origin */ - r_p[0] = (p[0] - cent[0]) / asp[0]; - r_p[1] = (p[1] - cent[1]) / asp[1]; + /* translate point back to origin */ + r_p[0] = (p[0] - cent[0]) / asp[0]; + r_p[1] = (p[1] - cent[1]) / asp[1]; - /* rotate point */ - p_new[0] = ((r_p[0] * c) - (r_p[1] * s)) * asp[0]; - p_new[1] = ((r_p[0] * s) + (r_p[1] * c)) * asp[1]; + /* rotate point */ + p_new[0] = ((r_p[0] * c) - (r_p[1] * s)) * asp[0]; + p_new[1] = ((r_p[0] * s) + (r_p[1] * c)) * asp[1]; - /* translate point back */ - r_p[0] = p_new[0] + cent[0]; - r_p[1] = p_new[1] + cent[1]; + /* translate point back */ + r_p[0] = p_new[0] + cent[0]; + r_p[1] = p_new[1] + cent[1]; } -BLI_INLINE unsigned int clampis_uint(const unsigned int v, const unsigned int min, const unsigned int max) +BLI_INLINE unsigned int clampis_uint(const unsigned int v, + const unsigned int min, + const unsigned int max) { - return v < min ? min : (v > max ? max : v); + return v < min ? min : (v > max ? max : v); } /* --------------------------------------------------------------------- */ @@ -151,54 +155,51 @@ BLI_INLINE unsigned int clampis_uint(const unsigned int v, const unsigned int mi /* internal use only */ typedef struct MaskRasterLayer { - /* geometry */ - unsigned int face_tot; - unsigned int (*face_array)[4]; /* access coords tri/quad */ - float (*face_coords)[3]; /* xy, z 0-1 (1.0 == filled) */ - - - /* 2d bounds (to quickly skip bucket lookup) */ - rctf bounds; - - - /* buckets */ - unsigned int **buckets_face; - /* cache divide and subtract */ - float buckets_xy_scalar[2]; /* (1.0 / (buckets_width + FLT_EPSILON)) * buckets_x */ - unsigned int buckets_x; - unsigned int buckets_y; - - - /* copied direct from #MaskLayer.--- */ - /* blending options */ - float alpha; - char blend; - char blend_flag; - char falloff; + /* geometry */ + unsigned int face_tot; + unsigned int (*face_array)[4]; /* access coords tri/quad */ + float (*face_coords)[3]; /* xy, z 0-1 (1.0 == filled) */ + + /* 2d bounds (to quickly skip bucket lookup) */ + rctf bounds; + + /* buckets */ + unsigned int **buckets_face; + /* cache divide and subtract */ + float buckets_xy_scalar[2]; /* (1.0 / (buckets_width + FLT_EPSILON)) * buckets_x */ + unsigned int buckets_x; + unsigned int buckets_y; + + /* copied direct from #MaskLayer.--- */ + /* blending options */ + float alpha; + char blend; + char blend_flag; + char falloff; } MaskRasterLayer; typedef struct MaskRasterSplineInfo { - /* body of the spline */ - unsigned int vertex_offset; - unsigned int vertex_total; + /* body of the spline */ + unsigned int vertex_offset; + unsigned int vertex_total; - /* capping for non-filled, non cyclic splines */ - unsigned int vertex_total_cap_head; - unsigned int vertex_total_cap_tail; + /* capping for non-filled, non cyclic splines */ + unsigned int vertex_total_cap_head; + unsigned int vertex_total_cap_tail; - bool is_cyclic; + bool is_cyclic; } MaskRasterSplineInfo; /** * opaque local struct for mask pixel lookup, each MaskLayer needs one of these */ struct MaskRasterHandle { - MaskRasterLayer *layers; - unsigned int layers_tot; + MaskRasterLayer *layers; + unsigned int layers_tot; - /* 2d bounds (to quickly skip bucket lookup) */ - rctf bounds; + /* 2d bounds (to quickly skip bucket lookup) */ + rctf bounds; }; /* --------------------------------------------------------------------- */ @@ -207,107 +208,107 @@ struct MaskRasterHandle { MaskRasterHandle *BKE_maskrasterize_handle_new(void) { - MaskRasterHandle *mr_handle; + MaskRasterHandle *mr_handle; - mr_handle = MEM_callocN(sizeof(MaskRasterHandle), "MaskRasterHandle"); + mr_handle = MEM_callocN(sizeof(MaskRasterHandle), "MaskRasterHandle"); - return mr_handle; + return mr_handle; } void BKE_maskrasterize_handle_free(MaskRasterHandle *mr_handle) { - const unsigned int layers_tot = mr_handle->layers_tot; - unsigned int i; - MaskRasterLayer *layer = mr_handle->layers; - - for (i = 0; i < layers_tot; i++, layer++) { - - if (layer->face_array) { - MEM_freeN(layer->face_array); - } - - if (layer->face_coords) { - MEM_freeN(layer->face_coords); - } - - if (layer->buckets_face) { - const unsigned int bucket_tot = layer->buckets_x * layer->buckets_y; - unsigned int bucket_index; - for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) { - unsigned int *face_index = layer->buckets_face[bucket_index]; - if (face_index) { - MEM_freeN(face_index); - } - } - - MEM_freeN(layer->buckets_face); - } - } - - MEM_freeN(mr_handle->layers); - MEM_freeN(mr_handle); + const unsigned int layers_tot = mr_handle->layers_tot; + unsigned int i; + MaskRasterLayer *layer = mr_handle->layers; + + for (i = 0; i < layers_tot; i++, layer++) { + + if (layer->face_array) { + MEM_freeN(layer->face_array); + } + + if (layer->face_coords) { + MEM_freeN(layer->face_coords); + } + + if (layer->buckets_face) { + const unsigned int bucket_tot = layer->buckets_x * layer->buckets_y; + unsigned int bucket_index; + for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) { + unsigned int *face_index = layer->buckets_face[bucket_index]; + if (face_index) { + MEM_freeN(face_index); + } + } + + MEM_freeN(layer->buckets_face); + } + } + + MEM_freeN(mr_handle->layers); + MEM_freeN(mr_handle); } - -static void maskrasterize_spline_differentiate_point_outset(float (*diff_feather_points)[2], float (*diff_points)[2], - const unsigned int tot_diff_point, const float ofs, +static void maskrasterize_spline_differentiate_point_outset(float (*diff_feather_points)[2], + float (*diff_points)[2], + const unsigned int tot_diff_point, + const float ofs, const bool do_test) { - unsigned int k_prev = tot_diff_point - 2; - unsigned int k_curr = tot_diff_point - 1; - unsigned int k_next = 0; + unsigned int k_prev = tot_diff_point - 2; + unsigned int k_curr = tot_diff_point - 1; + unsigned int k_next = 0; - unsigned int k; + unsigned int k; - float d_prev[2]; - float d_next[2]; - float d[2]; + float d_prev[2]; + float d_next[2]; + float d[2]; - const float *co_prev; - const float *co_curr; - const float *co_next; + const float *co_prev; + const float *co_curr; + const float *co_next; - const float ofs_squared = ofs * ofs; + const float ofs_squared = ofs * ofs; - co_prev = diff_points[k_prev]; - co_curr = diff_points[k_curr]; - co_next = diff_points[k_next]; + co_prev = diff_points[k_prev]; + co_curr = diff_points[k_curr]; + co_next = diff_points[k_next]; - /* precalc */ - sub_v2_v2v2(d_prev, co_prev, co_curr); - normalize_v2(d_prev); + /* precalc */ + sub_v2_v2v2(d_prev, co_prev, co_curr); + normalize_v2(d_prev); - for (k = 0; k < tot_diff_point; k++) { + for (k = 0; k < tot_diff_point; k++) { - /* co_prev = diff_points[k_prev]; */ /* precalc */ - co_curr = diff_points[k_curr]; - co_next = diff_points[k_next]; + /* co_prev = diff_points[k_prev]; */ /* precalc */ + co_curr = diff_points[k_curr]; + co_next = diff_points[k_next]; - /* sub_v2_v2v2(d_prev, co_prev, co_curr); */ /* precalc */ - sub_v2_v2v2(d_next, co_curr, co_next); + /* sub_v2_v2v2(d_prev, co_prev, co_curr); */ /* precalc */ + sub_v2_v2v2(d_next, co_curr, co_next); - /* normalize_v2(d_prev); */ /* precalc */ - normalize_v2(d_next); + /* normalize_v2(d_prev); */ /* precalc */ + normalize_v2(d_next); - if ((do_test == false) || - (len_squared_v2v2(diff_feather_points[k], diff_points[k]) < ofs_squared)) - { + if ((do_test == false) || + (len_squared_v2v2(diff_feather_points[k], diff_points[k]) < ofs_squared)) { - add_v2_v2v2(d, d_prev, d_next); + add_v2_v2v2(d, d_prev, d_next); - normalize_v2(d); + normalize_v2(d); - diff_feather_points[k][0] = diff_points[k][0] + ( d[1] * ofs); - diff_feather_points[k][1] = diff_points[k][1] + (-d[0] * ofs); - } + diff_feather_points[k][0] = diff_points[k][0] + (d[1] * ofs); + diff_feather_points[k][1] = diff_points[k][1] + (-d[0] * ofs); + } - /* use next iter */ - copy_v2_v2(d_prev, d_next); + /* use next iter */ + copy_v2_v2(d_prev, d_next); - /* k_prev = k_curr; */ /* precalc */ - k_curr = k_next; - k_next++; - } + /* k_prev = k_curr; */ /* precalc */ + k_curr = k_next; + k_next++; + } } /* this function is not exact, sometimes it returns false positives, @@ -319,876 +320,891 @@ static void maskrasterize_spline_differentiate_point_outset(float (*diff_feather * - if not get the max radius to a corner of the bucket and see how close we * are to any of the triangle edges. */ -static bool layer_bucket_isect_test( - const MaskRasterLayer *layer, unsigned int face_index, - const unsigned int bucket_x, const unsigned int bucket_y, - const float bucket_size_x, const float bucket_size_y, - const float bucket_max_rad_squared) +static bool layer_bucket_isect_test(const MaskRasterLayer *layer, + unsigned int face_index, + const unsigned int bucket_x, + const unsigned int bucket_y, + const float bucket_size_x, + const float bucket_size_y, + const float bucket_max_rad_squared) { - unsigned int *face = layer->face_array[face_index]; - float (*cos)[3] = layer->face_coords; - - const float xmin = layer->bounds.xmin + (bucket_size_x * (float)bucket_x); - const float ymin = layer->bounds.ymin + (bucket_size_y * (float)bucket_y); - const float xmax = xmin + bucket_size_x; - const float ymax = ymin + bucket_size_y; - - const float cent[2] = {(xmin + xmax) * 0.5f, - (ymin + ymax) * 0.5f}; - - if (face[3] == TRI_VERT) { - const float *v1 = cos[face[0]]; - const float *v2 = cos[face[1]]; - const float *v3 = cos[face[2]]; - - if (isect_point_tri_v2(cent, v1, v2, v3)) { - return true; - } - else { - if ((dist_squared_to_line_segment_v2(cent, v1, v2) < bucket_max_rad_squared) || - (dist_squared_to_line_segment_v2(cent, v2, v3) < bucket_max_rad_squared) || - (dist_squared_to_line_segment_v2(cent, v3, v1) < bucket_max_rad_squared)) - { - return true; - } - else { - // printf("skip tri\n"); - return false; - } - } - - } - else { - const float *v1 = cos[face[0]]; - const float *v2 = cos[face[1]]; - const float *v3 = cos[face[2]]; - const float *v4 = cos[face[3]]; - - if (isect_point_tri_v2(cent, v1, v2, v3)) { - return true; - } - else if (isect_point_tri_v2(cent, v1, v3, v4)) { - return true; - } - else { - if ((dist_squared_to_line_segment_v2(cent, v1, v2) < bucket_max_rad_squared) || - (dist_squared_to_line_segment_v2(cent, v2, v3) < bucket_max_rad_squared) || - (dist_squared_to_line_segment_v2(cent, v3, v4) < bucket_max_rad_squared) || - (dist_squared_to_line_segment_v2(cent, v4, v1) < bucket_max_rad_squared)) - { - return true; - } - else { - // printf("skip quad\n"); - return false; - } - } - } + unsigned int *face = layer->face_array[face_index]; + float(*cos)[3] = layer->face_coords; + + const float xmin = layer->bounds.xmin + (bucket_size_x * (float)bucket_x); + const float ymin = layer->bounds.ymin + (bucket_size_y * (float)bucket_y); + const float xmax = xmin + bucket_size_x; + const float ymax = ymin + bucket_size_y; + + const float cent[2] = {(xmin + xmax) * 0.5f, (ymin + ymax) * 0.5f}; + + if (face[3] == TRI_VERT) { + const float *v1 = cos[face[0]]; + const float *v2 = cos[face[1]]; + const float *v3 = cos[face[2]]; + + if (isect_point_tri_v2(cent, v1, v2, v3)) { + return true; + } + else { + if ((dist_squared_to_line_segment_v2(cent, v1, v2) < bucket_max_rad_squared) || + (dist_squared_to_line_segment_v2(cent, v2, v3) < bucket_max_rad_squared) || + (dist_squared_to_line_segment_v2(cent, v3, v1) < bucket_max_rad_squared)) { + return true; + } + else { + // printf("skip tri\n"); + return false; + } + } + } + else { + const float *v1 = cos[face[0]]; + const float *v2 = cos[face[1]]; + const float *v3 = cos[face[2]]; + const float *v4 = cos[face[3]]; + + if (isect_point_tri_v2(cent, v1, v2, v3)) { + return true; + } + else if (isect_point_tri_v2(cent, v1, v3, v4)) { + return true; + } + else { + if ((dist_squared_to_line_segment_v2(cent, v1, v2) < bucket_max_rad_squared) || + (dist_squared_to_line_segment_v2(cent, v2, v3) < bucket_max_rad_squared) || + (dist_squared_to_line_segment_v2(cent, v3, v4) < bucket_max_rad_squared) || + (dist_squared_to_line_segment_v2(cent, v4, v1) < bucket_max_rad_squared)) { + return true; + } + else { + // printf("skip quad\n"); + return false; + } + } + } } static void layer_bucket_init_dummy(MaskRasterLayer *layer) { - layer->face_tot = 0; - layer->face_coords = NULL; - layer->face_array = NULL; + layer->face_tot = 0; + layer->face_coords = NULL; + layer->face_array = NULL; - layer->buckets_x = 0; - layer->buckets_y = 0; + layer->buckets_x = 0; + layer->buckets_y = 0; - layer->buckets_xy_scalar[0] = 0.0f; - layer->buckets_xy_scalar[1] = 0.0f; + layer->buckets_xy_scalar[0] = 0.0f; + layer->buckets_xy_scalar[1] = 0.0f; - layer->buckets_face = NULL; + layer->buckets_face = NULL; - BLI_rctf_init(&layer->bounds, -1.0f, -1.0f, -1.0f, -1.0f); + BLI_rctf_init(&layer->bounds, -1.0f, -1.0f, -1.0f, -1.0f); } static void layer_bucket_init(MaskRasterLayer *layer, const float pixel_size) { - MemArena *arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), __func__); - - const float bucket_dim_x = BLI_rctf_size_x(&layer->bounds); - const float bucket_dim_y = BLI_rctf_size_y(&layer->bounds); - - layer->buckets_x = (unsigned int)((bucket_dim_x / pixel_size) / (float)BUCKET_PIXELS_PER_CELL); - layer->buckets_y = (unsigned int)((bucket_dim_y / pixel_size) / (float)BUCKET_PIXELS_PER_CELL); - -// printf("bucket size %ux%u\n", layer->buckets_x, layer->buckets_y); - - CLAMP(layer->buckets_x, 8, 512); - CLAMP(layer->buckets_y, 8, 512); - - layer->buckets_xy_scalar[0] = (1.0f / (bucket_dim_x + FLT_EPSILON)) * (float)layer->buckets_x; - layer->buckets_xy_scalar[1] = (1.0f / (bucket_dim_y + FLT_EPSILON)) * (float)layer->buckets_y; - - { - /* width and height of each bucket */ - const float bucket_size_x = (bucket_dim_x + FLT_EPSILON) / (float)layer->buckets_x; - const float bucket_size_y = (bucket_dim_y + FLT_EPSILON) / (float)layer->buckets_y; - const float bucket_max_rad = (max_ff(bucket_size_x, bucket_size_y) * (float)M_SQRT2) + FLT_EPSILON; - const float bucket_max_rad_squared = bucket_max_rad * bucket_max_rad; - - unsigned int *face = &layer->face_array[0][0]; - float (*cos)[3] = layer->face_coords; - - const unsigned int bucket_tot = layer->buckets_x * layer->buckets_y; - LinkNode **bucketstore = MEM_callocN(bucket_tot * sizeof(LinkNode *), __func__); - unsigned int *bucketstore_tot = MEM_callocN(bucket_tot * sizeof(unsigned int), __func__); - - unsigned int face_index; - - for (face_index = 0; face_index < layer->face_tot; face_index++, face += 4) { - float xmin; - float xmax; - float ymin; - float ymax; - - if (face[3] == TRI_VERT) { - const float *v1 = cos[face[0]]; - const float *v2 = cos[face[1]]; - const float *v3 = cos[face[2]]; - - xmin = min_ff(v1[0], min_ff(v2[0], v3[0])); - xmax = max_ff(v1[0], max_ff(v2[0], v3[0])); - ymin = min_ff(v1[1], min_ff(v2[1], v3[1])); - ymax = max_ff(v1[1], max_ff(v2[1], v3[1])); - } - else { - const float *v1 = cos[face[0]]; - const float *v2 = cos[face[1]]; - const float *v3 = cos[face[2]]; - const float *v4 = cos[face[3]]; - - xmin = min_ff(v1[0], min_ff(v2[0], min_ff(v3[0], v4[0]))); - xmax = max_ff(v1[0], max_ff(v2[0], max_ff(v3[0], v4[0]))); - ymin = min_ff(v1[1], min_ff(v2[1], min_ff(v3[1], v4[1]))); - ymax = max_ff(v1[1], max_ff(v2[1], max_ff(v3[1], v4[1]))); - } - - - /* not essential but may as will skip any faces outside the view */ - if (!((xmax < 0.0f) || (ymax < 0.0f) || (xmin > 1.0f) || (ymin > 1.0f))) { - - CLAMP(xmin, 0.0f, 1.0f); - CLAMP(ymin, 0.0f, 1.0f); - CLAMP(xmax, 0.0f, 1.0f); - CLAMP(ymax, 0.0f, 1.0f); - - { - unsigned int xi_min = (unsigned int) ((xmin - layer->bounds.xmin) * layer->buckets_xy_scalar[0]); - unsigned int xi_max = (unsigned int) ((xmax - layer->bounds.xmin) * layer->buckets_xy_scalar[0]); - unsigned int yi_min = (unsigned int) ((ymin - layer->bounds.ymin) * layer->buckets_xy_scalar[1]); - unsigned int yi_max = (unsigned int) ((ymax - layer->bounds.ymin) * layer->buckets_xy_scalar[1]); - void *face_index_void = POINTER_FROM_UINT(face_index); - - unsigned int xi, yi; - - /* this should _almost_ never happen but since it can in extreme cases, - * we have to clamp the values or we overrun the buffer and crash */ - if (xi_min >= layer->buckets_x) xi_min = layer->buckets_x - 1; - if (xi_max >= layer->buckets_x) xi_max = layer->buckets_x - 1; - if (yi_min >= layer->buckets_y) yi_min = layer->buckets_y - 1; - if (yi_max >= layer->buckets_y) yi_max = layer->buckets_y - 1; - - for (yi = yi_min; yi <= yi_max; yi++) { - unsigned int bucket_index = (layer->buckets_x * yi) + xi_min; - for (xi = xi_min; xi <= xi_max; xi++, bucket_index++) { - // unsigned int bucket_index = (layer->buckets_x * yi) + xi; /* correct but do in outer loop */ - - BLI_assert(xi < layer->buckets_x); - BLI_assert(yi < layer->buckets_y); - BLI_assert(bucket_index < bucket_tot); - - /* check if the bucket intersects with the face */ - /* note: there is a trade off here since checking box/tri intersections isn't - * as optimal as it could be, but checking pixels against faces they will never intersect - * with is likely the greater slowdown here - so check if the cell intersects the face */ - if (layer_bucket_isect_test(layer, face_index, - xi, yi, - bucket_size_x, bucket_size_y, - bucket_max_rad_squared)) - { - BLI_linklist_prepend_arena(&bucketstore[bucket_index], face_index_void, arena); - bucketstore_tot[bucket_index]++; - } - } - } - } - } - } - - if (1) { - /* now convert linknodes into arrays for faster per pixel access */ - unsigned int **buckets_face = MEM_mallocN(bucket_tot * sizeof(*buckets_face), __func__); - unsigned int bucket_index; - - for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) { - if (bucketstore_tot[bucket_index]) { - unsigned int *bucket = MEM_mallocN((bucketstore_tot[bucket_index] + 1) * sizeof(unsigned int), - __func__); - LinkNode *bucket_node; - - buckets_face[bucket_index] = bucket; - - for (bucket_node = bucketstore[bucket_index]; bucket_node; bucket_node = bucket_node->next) { - *bucket = POINTER_AS_UINT(bucket_node->link); - bucket++; - } - *bucket = TRI_TERMINATOR_ID; - } - else { - buckets_face[bucket_index] = NULL; - } - } - - layer->buckets_face = buckets_face; - } - - MEM_freeN(bucketstore); - MEM_freeN(bucketstore_tot); - } - - BLI_memarena_free(arena); + MemArena *arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), __func__); + + const float bucket_dim_x = BLI_rctf_size_x(&layer->bounds); + const float bucket_dim_y = BLI_rctf_size_y(&layer->bounds); + + layer->buckets_x = (unsigned int)((bucket_dim_x / pixel_size) / (float)BUCKET_PIXELS_PER_CELL); + layer->buckets_y = (unsigned int)((bucket_dim_y / pixel_size) / (float)BUCKET_PIXELS_PER_CELL); + + // printf("bucket size %ux%u\n", layer->buckets_x, layer->buckets_y); + + CLAMP(layer->buckets_x, 8, 512); + CLAMP(layer->buckets_y, 8, 512); + + layer->buckets_xy_scalar[0] = (1.0f / (bucket_dim_x + FLT_EPSILON)) * (float)layer->buckets_x; + layer->buckets_xy_scalar[1] = (1.0f / (bucket_dim_y + FLT_EPSILON)) * (float)layer->buckets_y; + + { + /* width and height of each bucket */ + const float bucket_size_x = (bucket_dim_x + FLT_EPSILON) / (float)layer->buckets_x; + const float bucket_size_y = (bucket_dim_y + FLT_EPSILON) / (float)layer->buckets_y; + const float bucket_max_rad = (max_ff(bucket_size_x, bucket_size_y) * (float)M_SQRT2) + + FLT_EPSILON; + const float bucket_max_rad_squared = bucket_max_rad * bucket_max_rad; + + unsigned int *face = &layer->face_array[0][0]; + float(*cos)[3] = layer->face_coords; + + const unsigned int bucket_tot = layer->buckets_x * layer->buckets_y; + LinkNode **bucketstore = MEM_callocN(bucket_tot * sizeof(LinkNode *), __func__); + unsigned int *bucketstore_tot = MEM_callocN(bucket_tot * sizeof(unsigned int), __func__); + + unsigned int face_index; + + for (face_index = 0; face_index < layer->face_tot; face_index++, face += 4) { + float xmin; + float xmax; + float ymin; + float ymax; + + if (face[3] == TRI_VERT) { + const float *v1 = cos[face[0]]; + const float *v2 = cos[face[1]]; + const float *v3 = cos[face[2]]; + + xmin = min_ff(v1[0], min_ff(v2[0], v3[0])); + xmax = max_ff(v1[0], max_ff(v2[0], v3[0])); + ymin = min_ff(v1[1], min_ff(v2[1], v3[1])); + ymax = max_ff(v1[1], max_ff(v2[1], v3[1])); + } + else { + const float *v1 = cos[face[0]]; + const float *v2 = cos[face[1]]; + const float *v3 = cos[face[2]]; + const float *v4 = cos[face[3]]; + + xmin = min_ff(v1[0], min_ff(v2[0], min_ff(v3[0], v4[0]))); + xmax = max_ff(v1[0], max_ff(v2[0], max_ff(v3[0], v4[0]))); + ymin = min_ff(v1[1], min_ff(v2[1], min_ff(v3[1], v4[1]))); + ymax = max_ff(v1[1], max_ff(v2[1], max_ff(v3[1], v4[1]))); + } + + /* not essential but may as will skip any faces outside the view */ + if (!((xmax < 0.0f) || (ymax < 0.0f) || (xmin > 1.0f) || (ymin > 1.0f))) { + + CLAMP(xmin, 0.0f, 1.0f); + CLAMP(ymin, 0.0f, 1.0f); + CLAMP(xmax, 0.0f, 1.0f); + CLAMP(ymax, 0.0f, 1.0f); + + { + unsigned int xi_min = (unsigned int)((xmin - layer->bounds.xmin) * + layer->buckets_xy_scalar[0]); + unsigned int xi_max = (unsigned int)((xmax - layer->bounds.xmin) * + layer->buckets_xy_scalar[0]); + unsigned int yi_min = (unsigned int)((ymin - layer->bounds.ymin) * + layer->buckets_xy_scalar[1]); + unsigned int yi_max = (unsigned int)((ymax - layer->bounds.ymin) * + layer->buckets_xy_scalar[1]); + void *face_index_void = POINTER_FROM_UINT(face_index); + + unsigned int xi, yi; + + /* this should _almost_ never happen but since it can in extreme cases, + * we have to clamp the values or we overrun the buffer and crash */ + if (xi_min >= layer->buckets_x) + xi_min = layer->buckets_x - 1; + if (xi_max >= layer->buckets_x) + xi_max = layer->buckets_x - 1; + if (yi_min >= layer->buckets_y) + yi_min = layer->buckets_y - 1; + if (yi_max >= layer->buckets_y) + yi_max = layer->buckets_y - 1; + + for (yi = yi_min; yi <= yi_max; yi++) { + unsigned int bucket_index = (layer->buckets_x * yi) + xi_min; + for (xi = xi_min; xi <= xi_max; xi++, bucket_index++) { + // unsigned int bucket_index = (layer->buckets_x * yi) + xi; /* correct but do in outer loop */ + + BLI_assert(xi < layer->buckets_x); + BLI_assert(yi < layer->buckets_y); + BLI_assert(bucket_index < bucket_tot); + + /* check if the bucket intersects with the face */ + /* note: there is a trade off here since checking box/tri intersections isn't + * as optimal as it could be, but checking pixels against faces they will never intersect + * with is likely the greater slowdown here - so check if the cell intersects the face */ + if (layer_bucket_isect_test(layer, + face_index, + xi, + yi, + bucket_size_x, + bucket_size_y, + bucket_max_rad_squared)) { + BLI_linklist_prepend_arena(&bucketstore[bucket_index], face_index_void, arena); + bucketstore_tot[bucket_index]++; + } + } + } + } + } + } + + if (1) { + /* now convert linknodes into arrays for faster per pixel access */ + unsigned int **buckets_face = MEM_mallocN(bucket_tot * sizeof(*buckets_face), __func__); + unsigned int bucket_index; + + for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) { + if (bucketstore_tot[bucket_index]) { + unsigned int *bucket = MEM_mallocN( + (bucketstore_tot[bucket_index] + 1) * sizeof(unsigned int), __func__); + LinkNode *bucket_node; + + buckets_face[bucket_index] = bucket; + + for (bucket_node = bucketstore[bucket_index]; bucket_node; + bucket_node = bucket_node->next) { + *bucket = POINTER_AS_UINT(bucket_node->link); + bucket++; + } + *bucket = TRI_TERMINATOR_ID; + } + else { + buckets_face[bucket_index] = NULL; + } + } + + layer->buckets_face = buckets_face; + } + + MEM_freeN(bucketstore); + MEM_freeN(bucketstore_tot); + } + + BLI_memarena_free(arena); } -void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mask, - const int width, const int height, - const bool do_aspect_correct, const bool do_mask_aa, +void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, + struct Mask *mask, + const int width, + const int height, + const bool do_aspect_correct, + const bool do_mask_aa, const bool do_feather) { - const rctf default_bounds = {0.0f, 1.0f, 0.0f, 1.0f}; - const float pixel_size = 1.0f / (float)min_ii(width, height); - const float asp_xy[2] = {(do_aspect_correct && width > height) ? (float)height / (float)width : 1.0f, - (do_aspect_correct && width < height) ? (float)width / (float)height : 1.0f}; + const rctf default_bounds = {0.0f, 1.0f, 0.0f, 1.0f}; + const float pixel_size = 1.0f / (float)min_ii(width, height); + const float asp_xy[2] = { + (do_aspect_correct && width > height) ? (float)height / (float)width : 1.0f, + (do_aspect_correct && width < height) ? (float)width / (float)height : 1.0f}; - const float zvec[3] = {0.0f, 0.0f, 1.0f}; - MaskLayer *masklay; - unsigned int masklay_index; - MemArena *sf_arena; + const float zvec[3] = {0.0f, 0.0f, 1.0f}; + MaskLayer *masklay; + unsigned int masklay_index; + MemArena *sf_arena; - mr_handle->layers_tot = (unsigned int)BLI_listbase_count(&mask->masklayers); - mr_handle->layers = MEM_mallocN(sizeof(MaskRasterLayer) * mr_handle->layers_tot, "MaskRasterLayer"); - BLI_rctf_init_minmax(&mr_handle->bounds); + mr_handle->layers_tot = (unsigned int)BLI_listbase_count(&mask->masklayers); + mr_handle->layers = MEM_mallocN(sizeof(MaskRasterLayer) * mr_handle->layers_tot, + "MaskRasterLayer"); + BLI_rctf_init_minmax(&mr_handle->bounds); - sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__); + sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__); - for (masklay = mask->masklayers.first, masklay_index = 0; masklay; masklay = masklay->next, masklay_index++) { + for (masklay = mask->masklayers.first, masklay_index = 0; masklay; + masklay = masklay->next, masklay_index++) { - /* we need to store vertex ranges for open splines for filling */ - unsigned int tot_splines; - MaskRasterSplineInfo *open_spline_ranges; - unsigned int open_spline_index = 0; + /* we need to store vertex ranges for open splines for filling */ + unsigned int tot_splines; + MaskRasterSplineInfo *open_spline_ranges; + unsigned int open_spline_index = 0; - MaskSpline *spline; + MaskSpline *spline; - /* scanfill */ - ScanFillContext sf_ctx; - ScanFillVert *sf_vert = NULL; - ScanFillVert *sf_vert_next = NULL; - ScanFillFace *sf_tri; + /* scanfill */ + ScanFillContext sf_ctx; + ScanFillVert *sf_vert = NULL; + ScanFillVert *sf_vert_next = NULL; + ScanFillFace *sf_tri; - unsigned int sf_vert_tot = 0; - unsigned int tot_feather_quads = 0; + unsigned int sf_vert_tot = 0; + unsigned int tot_feather_quads = 0; #ifdef USE_SCANFILL_EDGE_WORKAROUND - unsigned int tot_boundary_used = 0; - unsigned int tot_boundary_found = 0; + unsigned int tot_boundary_used = 0; + unsigned int tot_boundary_found = 0; #endif - if (masklay->restrictflag & MASK_RESTRICT_RENDER) { - /* skip the layer */ - mr_handle->layers_tot--; - masklay_index--; - continue; - } - - tot_splines = (unsigned int)BLI_listbase_count(&masklay->splines); - open_spline_ranges = MEM_callocN(sizeof(*open_spline_ranges) * tot_splines, __func__); - - BLI_scanfill_begin_arena(&sf_ctx, sf_arena); - - for (spline = masklay->splines.first; spline; spline = spline->next) { - const bool is_cyclic = (spline->flag & MASK_SPLINE_CYCLIC) != 0; - const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0; - - float (*diff_points)[2]; - unsigned int tot_diff_point; - - float (*diff_feather_points)[2]; - float (*diff_feather_points_flip)[2]; - unsigned int tot_diff_feather_points; - - const unsigned int resol_a = BKE_mask_spline_resolution(spline, width, height) / 4; - const unsigned int resol_b = BKE_mask_spline_feather_resolution(spline, width, height) / 4; - const unsigned int resol = CLAMPIS(MAX2(resol_a, resol_b), 4, 512); - - diff_points = BKE_mask_spline_differentiate_with_resolution( - spline, &tot_diff_point, resol); - - if (do_feather) { - diff_feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution( - spline, &tot_diff_feather_points, resol, false); - BLI_assert(diff_feather_points); - } - else { - tot_diff_feather_points = 0; - diff_feather_points = NULL; - } - - if (tot_diff_point > 3) { - ScanFillVert *sf_vert_prev; - unsigned int j; - - float co[3]; - co[2] = 0.0f; - - sf_ctx.poly_nr++; - - if (do_aspect_correct) { - if (width != height) { - float *fp; - float *ffp; - unsigned int i; - float asp; - - if (width < height) { - fp = &diff_points[0][0]; - ffp = tot_diff_feather_points ? &diff_feather_points[0][0] : NULL; - asp = (float)width / (float)height; - } - else { - fp = &diff_points[0][1]; - ffp = tot_diff_feather_points ? &diff_feather_points[0][1] : NULL; - asp = (float)height / (float)width; - } - - for (i = 0; i < tot_diff_point; i++, fp += 2) { - (*fp) = (((*fp) - 0.5f) / asp) + 0.5f; - } - - if (tot_diff_feather_points) { - for (i = 0; i < tot_diff_feather_points; i++, ffp += 2) { - (*ffp) = (((*ffp) - 0.5f) / asp) + 0.5f; - } - } - } - } - - /* fake aa, using small feather */ - if (do_mask_aa == true) { - if (do_feather == false) { - tot_diff_feather_points = tot_diff_point; - diff_feather_points = MEM_mallocN(sizeof(*diff_feather_points) * - (size_t)tot_diff_feather_points, - __func__); - /* add single pixel feather */ - maskrasterize_spline_differentiate_point_outset(diff_feather_points, diff_points, - tot_diff_point, pixel_size, false); - } - else { - /* ensure single pixel feather, on any zero feather areas */ - maskrasterize_spline_differentiate_point_outset(diff_feather_points, diff_points, - tot_diff_point, pixel_size, true); - } - } - - if (is_fill) { - /* applt intersections depending on fill settings */ - if (spline->flag & MASK_SPLINE_NOINTERSECT) { - BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points, tot_diff_feather_points); - } - - copy_v2_v2(co, diff_points[0]); - sf_vert_prev = BLI_scanfill_vert_add(&sf_ctx, co); - sf_vert_prev->tmp.u = sf_vert_tot; - sf_vert_prev->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */ - sf_vert_tot++; - - /* TODO, an alternate functions so we can avoid double vector copy! */ - for (j = 1; j < tot_diff_point; j++) { - copy_v2_v2(co, diff_points[j]); - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co); - sf_vert->tmp.u = sf_vert_tot; - sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */ - sf_vert_tot++; - } - - sf_vert = sf_vert_prev; - sf_vert_prev = sf_ctx.fillvertbase.last; - - for (j = 0; j < tot_diff_point; j++) { - ScanFillEdge *sf_edge = BLI_scanfill_edge_add(&sf_ctx, sf_vert_prev, sf_vert); + if (masklay->restrictflag & MASK_RESTRICT_RENDER) { + /* skip the layer */ + mr_handle->layers_tot--; + masklay_index--; + continue; + } + + tot_splines = (unsigned int)BLI_listbase_count(&masklay->splines); + open_spline_ranges = MEM_callocN(sizeof(*open_spline_ranges) * tot_splines, __func__); + + BLI_scanfill_begin_arena(&sf_ctx, sf_arena); + + for (spline = masklay->splines.first; spline; spline = spline->next) { + const bool is_cyclic = (spline->flag & MASK_SPLINE_CYCLIC) != 0; + const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0; + + float(*diff_points)[2]; + unsigned int tot_diff_point; + + float(*diff_feather_points)[2]; + float(*diff_feather_points_flip)[2]; + unsigned int tot_diff_feather_points; + + const unsigned int resol_a = BKE_mask_spline_resolution(spline, width, height) / 4; + const unsigned int resol_b = BKE_mask_spline_feather_resolution(spline, width, height) / 4; + const unsigned int resol = CLAMPIS(MAX2(resol_a, resol_b), 4, 512); + + diff_points = BKE_mask_spline_differentiate_with_resolution(spline, &tot_diff_point, resol); + + if (do_feather) { + diff_feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution( + spline, &tot_diff_feather_points, resol, false); + BLI_assert(diff_feather_points); + } + else { + tot_diff_feather_points = 0; + diff_feather_points = NULL; + } + + if (tot_diff_point > 3) { + ScanFillVert *sf_vert_prev; + unsigned int j; + + float co[3]; + co[2] = 0.0f; + + sf_ctx.poly_nr++; + + if (do_aspect_correct) { + if (width != height) { + float *fp; + float *ffp; + unsigned int i; + float asp; + + if (width < height) { + fp = &diff_points[0][0]; + ffp = tot_diff_feather_points ? &diff_feather_points[0][0] : NULL; + asp = (float)width / (float)height; + } + else { + fp = &diff_points[0][1]; + ffp = tot_diff_feather_points ? &diff_feather_points[0][1] : NULL; + asp = (float)height / (float)width; + } + + for (i = 0; i < tot_diff_point; i++, fp += 2) { + (*fp) = (((*fp) - 0.5f) / asp) + 0.5f; + } + + if (tot_diff_feather_points) { + for (i = 0; i < tot_diff_feather_points; i++, ffp += 2) { + (*ffp) = (((*ffp) - 0.5f) / asp) + 0.5f; + } + } + } + } + + /* fake aa, using small feather */ + if (do_mask_aa == true) { + if (do_feather == false) { + tot_diff_feather_points = tot_diff_point; + diff_feather_points = MEM_mallocN( + sizeof(*diff_feather_points) * (size_t)tot_diff_feather_points, __func__); + /* add single pixel feather */ + maskrasterize_spline_differentiate_point_outset( + diff_feather_points, diff_points, tot_diff_point, pixel_size, false); + } + else { + /* ensure single pixel feather, on any zero feather areas */ + maskrasterize_spline_differentiate_point_outset( + diff_feather_points, diff_points, tot_diff_point, pixel_size, true); + } + } + + if (is_fill) { + /* applt intersections depending on fill settings */ + if (spline->flag & MASK_SPLINE_NOINTERSECT) { + BKE_mask_spline_feather_collapse_inner_loops( + spline, diff_feather_points, tot_diff_feather_points); + } + + copy_v2_v2(co, diff_points[0]); + sf_vert_prev = BLI_scanfill_vert_add(&sf_ctx, co); + sf_vert_prev->tmp.u = sf_vert_tot; + sf_vert_prev->keyindex = sf_vert_tot + + tot_diff_point; /* absolute index of feather vert */ + sf_vert_tot++; + + /* TODO, an alternate functions so we can avoid double vector copy! */ + for (j = 1; j < tot_diff_point; j++) { + copy_v2_v2(co, diff_points[j]); + sf_vert = BLI_scanfill_vert_add(&sf_ctx, co); + sf_vert->tmp.u = sf_vert_tot; + sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */ + sf_vert_tot++; + } + + sf_vert = sf_vert_prev; + sf_vert_prev = sf_ctx.fillvertbase.last; + + for (j = 0; j < tot_diff_point; j++) { + ScanFillEdge *sf_edge = BLI_scanfill_edge_add(&sf_ctx, sf_vert_prev, sf_vert); #ifdef USE_SCANFILL_EDGE_WORKAROUND - if (diff_feather_points) { - sf_edge->tmp.c = SF_EDGE_IS_BOUNDARY; - tot_boundary_used++; - } + if (diff_feather_points) { + sf_edge->tmp.c = SF_EDGE_IS_BOUNDARY; + tot_boundary_used++; + } #else - (void)sf_edge; + (void)sf_edge; #endif - sf_vert_prev = sf_vert; - sf_vert = sf_vert->next; - } - - if (diff_feather_points) { - float co_feather[3]; - co_feather[2] = 1.0f; - - BLI_assert(tot_diff_feather_points == tot_diff_point); - - /* note: only added for convenience, we don't infact use these to scanfill, - * only to create feather faces after scanfill */ - for (j = 0; j < tot_diff_feather_points; j++) { - copy_v2_v2(co_feather, diff_feather_points[j]); - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); - sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; - sf_vert_tot++; - } - - tot_feather_quads += tot_diff_point; - } - } - else { - /* unfilled spline */ - if (diff_feather_points) { - - float co_diff[2]; - - float co_feather[3]; - co_feather[2] = 1.0f; - - if (spline->flag & MASK_SPLINE_NOINTERSECT) { - diff_feather_points_flip = MEM_mallocN(sizeof(float) * 2 * tot_diff_feather_points, "diff_feather_points_flip"); - - for (j = 0; j < tot_diff_point; j++) { - sub_v2_v2v2(co_diff, diff_points[j], diff_feather_points[j]); - add_v2_v2v2(diff_feather_points_flip[j], diff_points[j], co_diff); - } - - BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points, tot_diff_feather_points); - BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points_flip, tot_diff_feather_points); - } - else { - diff_feather_points_flip = NULL; - } - - - open_spline_ranges[open_spline_index].vertex_offset = sf_vert_tot; - open_spline_ranges[open_spline_index].vertex_total = tot_diff_point; - - /* TODO, an alternate functions so we can avoid double vector copy! */ - for (j = 0; j < tot_diff_point; j++) { - - /* center vert */ - copy_v2_v2(co, diff_points[j]); - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co); - sf_vert->tmp.u = sf_vert_tot; - sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; - sf_vert_tot++; - - - /* feather vert A */ - copy_v2_v2(co_feather, diff_feather_points[j]); - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); - sf_vert->tmp.u = sf_vert_tot; - sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; - sf_vert_tot++; - - - /* feather vert B */ - if (diff_feather_points_flip) { - copy_v2_v2(co_feather, diff_feather_points_flip[j]); - } - else { - sub_v2_v2v2(co_diff, co, co_feather); - add_v2_v2v2(co_feather, co, co_diff); - } - - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); - sf_vert->tmp.u = sf_vert_tot; - sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; - sf_vert_tot++; - - tot_feather_quads += 2; - } - - if (!is_cyclic) { - tot_feather_quads -= 2; - } - - if (diff_feather_points_flip) { - MEM_freeN(diff_feather_points_flip); - diff_feather_points_flip = NULL; - } - - /* cap ends */ - - /* dummy init value */ - open_spline_ranges[open_spline_index].vertex_total_cap_head = 0; - open_spline_ranges[open_spline_index].vertex_total_cap_tail = 0; - - if (!is_cyclic) { - const float *fp_cent; - const float *fp_turn; - - unsigned int k; - - fp_cent = diff_points[0]; - fp_turn = diff_feather_points[0]; - -#define CALC_CAP_RESOL \ - clampis_uint((unsigned int )(len_v2v2(fp_cent, fp_turn) / \ - (pixel_size * SPLINE_RESOL_CAP_PER_PIXEL)), \ - SPLINE_RESOL_CAP_MIN, SPLINE_RESOL_CAP_MAX) - - { - const unsigned int vertex_total_cap = CALC_CAP_RESOL; - - for (k = 1; k < vertex_total_cap; k++) { - const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI; - rotate_point_v2(co_feather, fp_turn, fp_cent, angle, asp_xy); - - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); - sf_vert->tmp.u = sf_vert_tot; - sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; - sf_vert_tot++; - } - tot_feather_quads += vertex_total_cap; - - open_spline_ranges[open_spline_index].vertex_total_cap_head = vertex_total_cap; - } - - fp_cent = diff_points[tot_diff_point - 1]; - fp_turn = diff_feather_points[tot_diff_point - 1]; - - { - const unsigned int vertex_total_cap = CALC_CAP_RESOL; - - for (k = 1; k < vertex_total_cap; k++) { - const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI; - rotate_point_v2(co_feather, fp_turn, fp_cent, -angle, asp_xy); - - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); - sf_vert->tmp.u = sf_vert_tot; - sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; - sf_vert_tot++; - } - tot_feather_quads += vertex_total_cap; - - open_spline_ranges[open_spline_index].vertex_total_cap_tail = vertex_total_cap; - } - } - - open_spline_ranges[open_spline_index].is_cyclic = is_cyclic; - open_spline_index++; + sf_vert_prev = sf_vert; + sf_vert = sf_vert->next; + } + + if (diff_feather_points) { + float co_feather[3]; + co_feather[2] = 1.0f; + + BLI_assert(tot_diff_feather_points == tot_diff_point); + + /* note: only added for convenience, we don't infact use these to scanfill, + * only to create feather faces after scanfill */ + for (j = 0; j < tot_diff_feather_points; j++) { + copy_v2_v2(co_feather, diff_feather_points[j]); + sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); + sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; + sf_vert_tot++; + } + + tot_feather_quads += tot_diff_point; + } + } + else { + /* unfilled spline */ + if (diff_feather_points) { + + float co_diff[2]; + + float co_feather[3]; + co_feather[2] = 1.0f; + + if (spline->flag & MASK_SPLINE_NOINTERSECT) { + diff_feather_points_flip = MEM_mallocN(sizeof(float) * 2 * tot_diff_feather_points, + "diff_feather_points_flip"); + + for (j = 0; j < tot_diff_point; j++) { + sub_v2_v2v2(co_diff, diff_points[j], diff_feather_points[j]); + add_v2_v2v2(diff_feather_points_flip[j], diff_points[j], co_diff); + } + + BKE_mask_spline_feather_collapse_inner_loops( + spline, diff_feather_points, tot_diff_feather_points); + BKE_mask_spline_feather_collapse_inner_loops( + spline, diff_feather_points_flip, tot_diff_feather_points); + } + else { + diff_feather_points_flip = NULL; + } + + open_spline_ranges[open_spline_index].vertex_offset = sf_vert_tot; + open_spline_ranges[open_spline_index].vertex_total = tot_diff_point; + + /* TODO, an alternate functions so we can avoid double vector copy! */ + for (j = 0; j < tot_diff_point; j++) { + + /* center vert */ + copy_v2_v2(co, diff_points[j]); + sf_vert = BLI_scanfill_vert_add(&sf_ctx, co); + sf_vert->tmp.u = sf_vert_tot; + sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; + sf_vert_tot++; + + /* feather vert A */ + copy_v2_v2(co_feather, diff_feather_points[j]); + sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); + sf_vert->tmp.u = sf_vert_tot; + sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; + sf_vert_tot++; + + /* feather vert B */ + if (diff_feather_points_flip) { + copy_v2_v2(co_feather, diff_feather_points_flip[j]); + } + else { + sub_v2_v2v2(co_diff, co, co_feather); + add_v2_v2v2(co_feather, co, co_diff); + } + + sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); + sf_vert->tmp.u = sf_vert_tot; + sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; + sf_vert_tot++; + + tot_feather_quads += 2; + } + + if (!is_cyclic) { + tot_feather_quads -= 2; + } + + if (diff_feather_points_flip) { + MEM_freeN(diff_feather_points_flip); + diff_feather_points_flip = NULL; + } + + /* cap ends */ + + /* dummy init value */ + open_spline_ranges[open_spline_index].vertex_total_cap_head = 0; + open_spline_ranges[open_spline_index].vertex_total_cap_tail = 0; + + if (!is_cyclic) { + const float *fp_cent; + const float *fp_turn; + + unsigned int k; + + fp_cent = diff_points[0]; + fp_turn = diff_feather_points[0]; + +#define CALC_CAP_RESOL \ + clampis_uint( \ + (unsigned int)(len_v2v2(fp_cent, fp_turn) / (pixel_size * SPLINE_RESOL_CAP_PER_PIXEL)), \ + SPLINE_RESOL_CAP_MIN, \ + SPLINE_RESOL_CAP_MAX) + + { + const unsigned int vertex_total_cap = CALC_CAP_RESOL; + + for (k = 1; k < vertex_total_cap; k++) { + const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI; + rotate_point_v2(co_feather, fp_turn, fp_cent, angle, asp_xy); + + sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); + sf_vert->tmp.u = sf_vert_tot; + sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; + sf_vert_tot++; + } + tot_feather_quads += vertex_total_cap; + + open_spline_ranges[open_spline_index].vertex_total_cap_head = vertex_total_cap; + } + + fp_cent = diff_points[tot_diff_point - 1]; + fp_turn = diff_feather_points[tot_diff_point - 1]; + + { + const unsigned int vertex_total_cap = CALC_CAP_RESOL; + + for (k = 1; k < vertex_total_cap; k++) { + const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI; + rotate_point_v2(co_feather, fp_turn, fp_cent, -angle, asp_xy); + + sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); + sf_vert->tmp.u = sf_vert_tot; + sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; + sf_vert_tot++; + } + tot_feather_quads += vertex_total_cap; + + open_spline_ranges[open_spline_index].vertex_total_cap_tail = vertex_total_cap; + } + } + + open_spline_ranges[open_spline_index].is_cyclic = is_cyclic; + open_spline_index++; #undef CALC_CAP_RESOL - /* end capping */ - - } - } - } - - if (diff_points) { - MEM_freeN(diff_points); - } - - if (diff_feather_points) { - MEM_freeN(diff_feather_points); - } - } - - { - unsigned int (*face_array)[4], *face; /* access coords */ - float (*face_coords)[3], *cos; /* xy, z 0-1 (1.0 == filled) */ - unsigned int sf_tri_tot; - rctf bounds; - unsigned int face_index; - int scanfill_flag = 0; - - bool is_isect = false; - ListBase isect_remvertbase = {NULL, NULL}; - ListBase isect_remedgebase = {NULL, NULL}; - - /* now we have all the splines */ - face_coords = MEM_mallocN((sizeof(float) * 3) * sf_vert_tot, "maskrast_face_coords"); - - /* init bounds */ - BLI_rctf_init_minmax(&bounds); - - /* coords */ - cos = (float *)face_coords; - for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert_next) { - sf_vert_next = sf_vert->next; - copy_v3_v3(cos, sf_vert->co); - - /* remove so as not to interfere with fill (called after) */ - if (sf_vert->keyindex == SF_KEYINDEX_TEMP_ID) { - BLI_remlink(&sf_ctx.fillvertbase, sf_vert); - } - - /* bounds */ - BLI_rctf_do_minmax_v(&bounds, cos); - - cos += 3; - } - - - /* --- inefficient self-intersect case --- */ - /* if self intersections are found, its too trickty to attempt to map vertices - * so just realloc and add entirely new vertices - the result of the self-intersect check - */ - if ((masklay->flag & MASK_LAYERFLAG_FILL_OVERLAP) && - (is_isect = BLI_scanfill_calc_self_isect(&sf_ctx, - &isect_remvertbase, - &isect_remedgebase))) - { - unsigned int sf_vert_tot_isect = (unsigned int)BLI_listbase_count(&sf_ctx.fillvertbase); - unsigned int i = sf_vert_tot; - - face_coords = MEM_reallocN(face_coords, sizeof(float[3]) * (sf_vert_tot + sf_vert_tot_isect)); - - cos = (float *)&face_coords[sf_vert_tot][0]; - - for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert->next) { - copy_v3_v3(cos, sf_vert->co); - sf_vert->tmp.u = i++; - cos += 3; - } - - sf_vert_tot += sf_vert_tot_isect; - - /* we need to calc polys after self intersect */ - scanfill_flag |= BLI_SCANFILL_CALC_POLYS; - } - /* --- end inefficient code --- */ - - - /* main scan-fill */ - if ((masklay->flag & MASK_LAYERFLAG_FILL_DISCRETE) == 0) - scanfill_flag |= BLI_SCANFILL_CALC_HOLES; - - sf_tri_tot = (unsigned int)BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, zvec); - - if (is_isect) { - /* add removed data back, we only need edges for feather, - * but add verts back so they get freed along with others */ - BLI_movelisttolist(&sf_ctx.fillvertbase, &isect_remvertbase); - BLI_movelisttolist(&sf_ctx.filledgebase, &isect_remedgebase); - } - - face_array = MEM_mallocN(sizeof(*face_array) * ((size_t)sf_tri_tot + (size_t)tot_feather_quads), "maskrast_face_index"); - face_index = 0; - - /* faces */ - face = (unsigned int *)face_array; - for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { - *(face++) = sf_tri->v3->tmp.u; - *(face++) = sf_tri->v2->tmp.u; - *(face++) = sf_tri->v1->tmp.u; - *(face++) = TRI_VERT; - face_index++; - FACE_ASSERT(face - 4, sf_vert_tot); - } - - /* start of feather faces... if we have this set, - * 'face_index' is kept from loop above */ - - BLI_assert(face_index == sf_tri_tot); - - if (tot_feather_quads) { - ScanFillEdge *sf_edge; - - for (sf_edge = sf_ctx.filledgebase.first; sf_edge; sf_edge = sf_edge->next) { - if (sf_edge->tmp.c == SF_EDGE_IS_BOUNDARY) { - *(face++) = sf_edge->v1->tmp.u; - *(face++) = sf_edge->v2->tmp.u; - *(face++) = sf_edge->v2->keyindex; - *(face++) = sf_edge->v1->keyindex; - face_index++; - FACE_ASSERT(face - 4, sf_vert_tot); + /* end capping */ + } + } + } + + if (diff_points) { + MEM_freeN(diff_points); + } + + if (diff_feather_points) { + MEM_freeN(diff_feather_points); + } + } + + { + unsigned int(*face_array)[4], *face; /* access coords */ + float(*face_coords)[3], *cos; /* xy, z 0-1 (1.0 == filled) */ + unsigned int sf_tri_tot; + rctf bounds; + unsigned int face_index; + int scanfill_flag = 0; + + bool is_isect = false; + ListBase isect_remvertbase = {NULL, NULL}; + ListBase isect_remedgebase = {NULL, NULL}; + + /* now we have all the splines */ + face_coords = MEM_mallocN((sizeof(float) * 3) * sf_vert_tot, "maskrast_face_coords"); + + /* init bounds */ + BLI_rctf_init_minmax(&bounds); + + /* coords */ + cos = (float *)face_coords; + for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert_next) { + sf_vert_next = sf_vert->next; + copy_v3_v3(cos, sf_vert->co); + + /* remove so as not to interfere with fill (called after) */ + if (sf_vert->keyindex == SF_KEYINDEX_TEMP_ID) { + BLI_remlink(&sf_ctx.fillvertbase, sf_vert); + } + + /* bounds */ + BLI_rctf_do_minmax_v(&bounds, cos); + + cos += 3; + } + + /* --- inefficient self-intersect case --- */ + /* if self intersections are found, its too trickty to attempt to map vertices + * so just realloc and add entirely new vertices - the result of the self-intersect check + */ + if ((masklay->flag & MASK_LAYERFLAG_FILL_OVERLAP) && + (is_isect = BLI_scanfill_calc_self_isect( + &sf_ctx, &isect_remvertbase, &isect_remedgebase))) { + unsigned int sf_vert_tot_isect = (unsigned int)BLI_listbase_count(&sf_ctx.fillvertbase); + unsigned int i = sf_vert_tot; + + face_coords = MEM_reallocN(face_coords, + sizeof(float[3]) * (sf_vert_tot + sf_vert_tot_isect)); + + cos = (float *)&face_coords[sf_vert_tot][0]; + + for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert->next) { + copy_v3_v3(cos, sf_vert->co); + sf_vert->tmp.u = i++; + cos += 3; + } + + sf_vert_tot += sf_vert_tot_isect; + + /* we need to calc polys after self intersect */ + scanfill_flag |= BLI_SCANFILL_CALC_POLYS; + } + /* --- end inefficient code --- */ + + /* main scan-fill */ + if ((masklay->flag & MASK_LAYERFLAG_FILL_DISCRETE) == 0) + scanfill_flag |= BLI_SCANFILL_CALC_HOLES; + + sf_tri_tot = (unsigned int)BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, zvec); + + if (is_isect) { + /* add removed data back, we only need edges for feather, + * but add verts back so they get freed along with others */ + BLI_movelisttolist(&sf_ctx.fillvertbase, &isect_remvertbase); + BLI_movelisttolist(&sf_ctx.filledgebase, &isect_remedgebase); + } + + face_array = MEM_mallocN(sizeof(*face_array) * + ((size_t)sf_tri_tot + (size_t)tot_feather_quads), + "maskrast_face_index"); + face_index = 0; + + /* faces */ + face = (unsigned int *)face_array; + for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { + *(face++) = sf_tri->v3->tmp.u; + *(face++) = sf_tri->v2->tmp.u; + *(face++) = sf_tri->v1->tmp.u; + *(face++) = TRI_VERT; + face_index++; + FACE_ASSERT(face - 4, sf_vert_tot); + } + + /* start of feather faces... if we have this set, + * 'face_index' is kept from loop above */ + + BLI_assert(face_index == sf_tri_tot); + + if (tot_feather_quads) { + ScanFillEdge *sf_edge; + + for (sf_edge = sf_ctx.filledgebase.first; sf_edge; sf_edge = sf_edge->next) { + if (sf_edge->tmp.c == SF_EDGE_IS_BOUNDARY) { + *(face++) = sf_edge->v1->tmp.u; + *(face++) = sf_edge->v2->tmp.u; + *(face++) = sf_edge->v2->keyindex; + *(face++) = sf_edge->v1->keyindex; + face_index++; + FACE_ASSERT(face - 4, sf_vert_tot); #ifdef USE_SCANFILL_EDGE_WORKAROUND - tot_boundary_found++; + tot_boundary_found++; #endif - } - } - } + } + } + } #ifdef USE_SCANFILL_EDGE_WORKAROUND - if (tot_boundary_found != tot_boundary_used) { - BLI_assert(tot_boundary_found < tot_boundary_used); - } + if (tot_boundary_found != tot_boundary_used) { + BLI_assert(tot_boundary_found < tot_boundary_used); + } #endif - /* feather only splines */ - while (open_spline_index > 0) { - const unsigned int vertex_offset = open_spline_ranges[--open_spline_index].vertex_offset; - unsigned int vertex_total = open_spline_ranges[ open_spline_index].vertex_total; - unsigned int vertex_total_cap_head = open_spline_ranges[ open_spline_index].vertex_total_cap_head; - unsigned int vertex_total_cap_tail = open_spline_ranges[ open_spline_index].vertex_total_cap_tail; - unsigned int k, j; - - j = vertex_offset; - - /* subtract one since we reference next vertex triple */ - for (k = 0; k < vertex_total - 1; k++, j += 3) { - - BLI_assert(j == vertex_offset + (k * 3)); - - *(face++) = j + 3; /* next span */ /* z 1 */ - *(face++) = j + 0; /* z 1 */ - *(face++) = j + 1; /* z 0 */ - *(face++) = j + 4; /* next span */ /* z 0 */ - face_index++; - FACE_ASSERT(face - 4, sf_vert_tot); - - *(face++) = j + 0; /* z 1 */ - *(face++) = j + 3; /* next span */ /* z 1 */ - *(face++) = j + 5; /* next span */ /* z 0 */ - *(face++) = j + 2; /* z 0 */ - face_index++; - FACE_ASSERT(face - 4, sf_vert_tot); - } - - if (open_spline_ranges[open_spline_index].is_cyclic) { - *(face++) = vertex_offset + 0; /* next span */ /* z 1 */ - *(face++) = j + 0; /* z 1 */ - *(face++) = j + 1; /* z 0 */ - *(face++) = vertex_offset + 1; /* next span */ /* z 0 */ - face_index++; - FACE_ASSERT(face - 4, sf_vert_tot); - - *(face++) = j + 0; /* z 1 */ - *(face++) = vertex_offset + 0; /* next span */ /* z 1 */ - *(face++) = vertex_offset + 2; /* next span */ /* z 0 */ - *(face++) = j + 2; /* z 0 */ - face_index++; - FACE_ASSERT(face - 4, sf_vert_tot); - } - else { - unsigned int midvidx = vertex_offset; - - /*************** - * cap end 'a' */ - j = midvidx + (vertex_total * 3); - - for (k = 0; k < vertex_total_cap_head - 2; k++, j++) { - *(face++) = midvidx + 0; /* z 1 */ - *(face++) = midvidx + 0; /* z 1 */ - *(face++) = j + 0; /* z 0 */ - *(face++) = j + 1; /* z 0 */ - face_index++; - FACE_ASSERT(face - 4, sf_vert_tot); - } - - j = vertex_offset + (vertex_total * 3); - - /* 2 tris that join the original */ - *(face++) = midvidx + 0; /* z 1 */ - *(face++) = midvidx + 0; /* z 1 */ - *(face++) = midvidx + 1; /* z 0 */ - *(face++) = j + 0; /* z 0 */ - face_index++; - FACE_ASSERT(face - 4, sf_vert_tot); - - *(face++) = midvidx + 0; /* z 1 */ - *(face++) = midvidx + 0; /* z 1 */ - *(face++) = j + vertex_total_cap_head - 2; /* z 0 */ - *(face++) = midvidx + 2; /* z 0 */ - face_index++; - FACE_ASSERT(face - 4, sf_vert_tot); - - - /*************** - * cap end 'b' */ - /* ... same as previous but v 2-3 flipped, and different initial offsets */ - - j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1); - - midvidx = vertex_offset + (vertex_total * 3) - 3; - - for (k = 0; k < vertex_total_cap_tail - 2; k++, j++) { - *(face++) = midvidx; /* z 1 */ - *(face++) = midvidx; /* z 1 */ - *(face++) = j + 1; /* z 0 */ - *(face++) = j + 0; /* z 0 */ - face_index++; - FACE_ASSERT(face - 4, sf_vert_tot); - } - - j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1); - - /* 2 tris that join the original */ - *(face++) = midvidx + 0; /* z 1 */ - *(face++) = midvidx + 0; /* z 1 */ - *(face++) = j + 0; /* z 0 */ - *(face++) = midvidx + 1; /* z 0 */ - face_index++; - FACE_ASSERT(face - 4, sf_vert_tot); - - *(face++) = midvidx + 0; /* z 1 */ - *(face++) = midvidx + 0; /* z 1 */ - *(face++) = midvidx + 2; /* z 0 */ - *(face++) = j + vertex_total_cap_tail - 2; /* z 0 */ - face_index++; - FACE_ASSERT(face - 4, sf_vert_tot); - - } - } - - MEM_freeN(open_spline_ranges); - -// fprintf(stderr, "%u %u (%u %u), %u\n", face_index, sf_tri_tot + tot_feather_quads, sf_tri_tot, tot_feather_quads, tot_boundary_used - tot_boundary_found); + /* feather only splines */ + while (open_spline_index > 0) { + const unsigned int vertex_offset = open_spline_ranges[--open_spline_index].vertex_offset; + unsigned int vertex_total = open_spline_ranges[open_spline_index].vertex_total; + unsigned int vertex_total_cap_head = + open_spline_ranges[open_spline_index].vertex_total_cap_head; + unsigned int vertex_total_cap_tail = + open_spline_ranges[open_spline_index].vertex_total_cap_tail; + unsigned int k, j; + + j = vertex_offset; + + /* subtract one since we reference next vertex triple */ + for (k = 0; k < vertex_total - 1; k++, j += 3) { + + BLI_assert(j == vertex_offset + (k * 3)); + + *(face++) = j + 3; /* next span */ /* z 1 */ + *(face++) = j + 0; /* z 1 */ + *(face++) = j + 1; /* z 0 */ + *(face++) = j + 4; /* next span */ /* z 0 */ + face_index++; + FACE_ASSERT(face - 4, sf_vert_tot); + + *(face++) = j + 0; /* z 1 */ + *(face++) = j + 3; /* next span */ /* z 1 */ + *(face++) = j + 5; /* next span */ /* z 0 */ + *(face++) = j + 2; /* z 0 */ + face_index++; + FACE_ASSERT(face - 4, sf_vert_tot); + } + + if (open_spline_ranges[open_spline_index].is_cyclic) { + *(face++) = vertex_offset + 0; /* next span */ /* z 1 */ + *(face++) = j + 0; /* z 1 */ + *(face++) = j + 1; /* z 0 */ + *(face++) = vertex_offset + 1; /* next span */ /* z 0 */ + face_index++; + FACE_ASSERT(face - 4, sf_vert_tot); + + *(face++) = j + 0; /* z 1 */ + *(face++) = vertex_offset + 0; /* next span */ /* z 1 */ + *(face++) = vertex_offset + 2; /* next span */ /* z 0 */ + *(face++) = j + 2; /* z 0 */ + face_index++; + FACE_ASSERT(face - 4, sf_vert_tot); + } + else { + unsigned int midvidx = vertex_offset; + + /*************** + * cap end 'a' */ + j = midvidx + (vertex_total * 3); + + for (k = 0; k < vertex_total_cap_head - 2; k++, j++) { + *(face++) = midvidx + 0; /* z 1 */ + *(face++) = midvidx + 0; /* z 1 */ + *(face++) = j + 0; /* z 0 */ + *(face++) = j + 1; /* z 0 */ + face_index++; + FACE_ASSERT(face - 4, sf_vert_tot); + } + + j = vertex_offset + (vertex_total * 3); + + /* 2 tris that join the original */ + *(face++) = midvidx + 0; /* z 1 */ + *(face++) = midvidx + 0; /* z 1 */ + *(face++) = midvidx + 1; /* z 0 */ + *(face++) = j + 0; /* z 0 */ + face_index++; + FACE_ASSERT(face - 4, sf_vert_tot); + + *(face++) = midvidx + 0; /* z 1 */ + *(face++) = midvidx + 0; /* z 1 */ + *(face++) = j + vertex_total_cap_head - 2; /* z 0 */ + *(face++) = midvidx + 2; /* z 0 */ + face_index++; + FACE_ASSERT(face - 4, sf_vert_tot); + + /*************** + * cap end 'b' */ + /* ... same as previous but v 2-3 flipped, and different initial offsets */ + + j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1); + + midvidx = vertex_offset + (vertex_total * 3) - 3; + + for (k = 0; k < vertex_total_cap_tail - 2; k++, j++) { + *(face++) = midvidx; /* z 1 */ + *(face++) = midvidx; /* z 1 */ + *(face++) = j + 1; /* z 0 */ + *(face++) = j + 0; /* z 0 */ + face_index++; + FACE_ASSERT(face - 4, sf_vert_tot); + } + + j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1); + + /* 2 tris that join the original */ + *(face++) = midvidx + 0; /* z 1 */ + *(face++) = midvidx + 0; /* z 1 */ + *(face++) = j + 0; /* z 0 */ + *(face++) = midvidx + 1; /* z 0 */ + face_index++; + FACE_ASSERT(face - 4, sf_vert_tot); + + *(face++) = midvidx + 0; /* z 1 */ + *(face++) = midvidx + 0; /* z 1 */ + *(face++) = midvidx + 2; /* z 0 */ + *(face++) = j + vertex_total_cap_tail - 2; /* z 0 */ + face_index++; + FACE_ASSERT(face - 4, sf_vert_tot); + } + } + + MEM_freeN(open_spline_ranges); + + // fprintf(stderr, "%u %u (%u %u), %u\n", face_index, sf_tri_tot + tot_feather_quads, sf_tri_tot, tot_feather_quads, tot_boundary_used - tot_boundary_found); #ifdef USE_SCANFILL_EDGE_WORKAROUND - BLI_assert(face_index + (tot_boundary_used - tot_boundary_found) == sf_tri_tot + tot_feather_quads); + BLI_assert(face_index + (tot_boundary_used - tot_boundary_found) == + sf_tri_tot + tot_feather_quads); #else - BLI_assert(face_index == sf_tri_tot + tot_feather_quads); + BLI_assert(face_index == sf_tri_tot + tot_feather_quads); #endif - { - MaskRasterLayer *layer = &mr_handle->layers[masklay_index]; + { + MaskRasterLayer *layer = &mr_handle->layers[masklay_index]; - if (BLI_rctf_isect(&default_bounds, &bounds, &bounds)) { + if (BLI_rctf_isect(&default_bounds, &bounds, &bounds)) { #ifdef USE_SCANFILL_EDGE_WORKAROUND - layer->face_tot = (sf_tri_tot + tot_feather_quads) - (tot_boundary_used - tot_boundary_found); + layer->face_tot = (sf_tri_tot + tot_feather_quads) - + (tot_boundary_used - tot_boundary_found); #else - layer->face_tot = (sf_tri_tot + tot_feather_quads); + layer->face_tot = (sf_tri_tot + tot_feather_quads); #endif - layer->face_coords = face_coords; - layer->face_array = face_array; - layer->bounds = bounds; + layer->face_coords = face_coords; + layer->face_array = face_array; + layer->bounds = bounds; - layer_bucket_init(layer, pixel_size); + layer_bucket_init(layer, pixel_size); - BLI_rctf_union(&mr_handle->bounds, &bounds); - } - else { - MEM_freeN(face_coords); - MEM_freeN(face_array); + BLI_rctf_union(&mr_handle->bounds, &bounds); + } + else { + MEM_freeN(face_coords); + MEM_freeN(face_array); - layer_bucket_init_dummy(layer); - } + layer_bucket_init_dummy(layer); + } - /* copy as-is */ - layer->alpha = masklay->alpha; - layer->blend = masklay->blend; - layer->blend_flag = masklay->blend_flag; - layer->falloff = masklay->falloff; - } + /* copy as-is */ + layer->alpha = masklay->alpha; + layer->blend = masklay->blend; + layer->blend_flag = masklay->blend_flag; + layer->falloff = masklay->falloff; + } - /* printf("tris %d, feather tris %d\n", sf_tri_tot, tot_feather_quads); */ - } + /* printf("tris %d, feather tris %d\n", sf_tri_tot, tot_feather_quads); */ + } - /* add trianges */ - BLI_scanfill_end_arena(&sf_ctx, sf_arena); - } + /* add trianges */ + BLI_scanfill_end_arena(&sf_ctx, sf_arena); + } - BLI_memarena_free(sf_arena); + BLI_memarena_free(sf_arena); } - /* --------------------------------------------------------------------- */ /* functions that run inside the sampling thread (keep fast!) */ /* --------------------------------------------------------------------- */ @@ -1198,274 +1214,273 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mas static float maskrasterize_layer_z_depth_tri(const float pt[2], const float v1[3], const float v2[3], const float v3[3]) { - float w[3]; - barycentric_weights_v2(v1, v2, v3, pt, w); - return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]); + float w[3]; + barycentric_weights_v2(v1, v2, v3, pt, w); + return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]); } #endif -static float maskrasterize_layer_z_depth_quad(const float pt[2], - const float v1[3], const float v2[3], const float v3[3], const float v4[3]) +static float maskrasterize_layer_z_depth_quad( + const float pt[2], const float v1[3], const float v2[3], const float v3[3], const float v4[3]) { - float w[4]; - barycentric_weights_v2_quad(v1, v2, v3, v4, pt, w); - //return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]) + (v4[2] * w[3]); - return w[2] + w[3]; /* we can make this assumption for small speedup */ + float w[4]; + barycentric_weights_v2_quad(v1, v2, v3, v4, pt, w); + //return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]) + (v4[2] * w[3]); + return w[2] + w[3]; /* we can make this assumption for small speedup */ } -static float maskrasterize_layer_isect(unsigned int *face, float (*cos)[3], const float dist_orig, const float xy[2]) +static float maskrasterize_layer_isect(unsigned int *face, + float (*cos)[3], + const float dist_orig, + const float xy[2]) { - /* we always cast from same place only need xy */ - if (face[3] == TRI_VERT) { - /* --- tri --- */ + /* we always cast from same place only need xy */ + if (face[3] == TRI_VERT) { + /* --- tri --- */ #if 0 - /* not essential but avoids unneeded extra lookups */ - if ((cos[0][2] < dist_orig) || - (cos[1][2] < dist_orig) || - (cos[2][2] < dist_orig)) - { - if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) { - /* we know all tris are close for now */ - return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[1]], cos[face[2]]); - } - } + /* not essential but avoids unneeded extra lookups */ + if ((cos[0][2] < dist_orig) || + (cos[1][2] < dist_orig) || + (cos[2][2] < dist_orig)) + { + if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) { + /* we know all tris are close for now */ + return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[1]], cos[face[2]]); + } + } #else - /* we know all tris are close for now */ - if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) { - return 0.0f; - } + /* we know all tris are close for now */ + if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) { + return 0.0f; + } #endif - } - else { - /* --- quad --- */ - - /* not essential but avoids unneeded extra lookups */ - if ((cos[0][2] < dist_orig) || - (cos[1][2] < dist_orig) || - (cos[2][2] < dist_orig) || - (cos[3][2] < dist_orig)) - { - - /* needs work */ + } + else { + /* --- quad --- */ + + /* not essential but avoids unneeded extra lookups */ + if ((cos[0][2] < dist_orig) || (cos[1][2] < dist_orig) || (cos[2][2] < dist_orig) || + (cos[3][2] < dist_orig)) { + + /* needs work */ #if 1 - /* quad check fails for bow-tie, so keep using 2 tri checks */ - //if (isect_point_quad_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]], cos[face[3]])) - if (isect_point_tri_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]]) || - isect_point_tri_v2(xy, cos[face[0]], cos[face[2]], cos[face[3]])) - { - return maskrasterize_layer_z_depth_quad(xy, cos[face[0]], cos[face[1]], cos[face[2]], cos[face[3]]); - } + /* quad check fails for bow-tie, so keep using 2 tri checks */ + //if (isect_point_quad_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]], cos[face[3]])) + if (isect_point_tri_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]]) || + isect_point_tri_v2(xy, cos[face[0]], cos[face[2]], cos[face[3]])) { + return maskrasterize_layer_z_depth_quad( + xy, cos[face[0]], cos[face[1]], cos[face[2]], cos[face[3]]); + } #elif 1 - /* don't use isect_point_tri_v2_cw because we could have bow-tie quads */ - - if (isect_point_tri_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]])) { - return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[1]], cos[face[2]]); - } - else if (isect_point_tri_v2(xy, cos[face[0]], cos[face[2]], cos[face[3]])) { - return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[2]], cos[face[3]]); - } + /* don't use isect_point_tri_v2_cw because we could have bow-tie quads */ + + if (isect_point_tri_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]])) { + return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[1]], cos[face[2]]); + } + else if (isect_point_tri_v2(xy, cos[face[0]], cos[face[2]], cos[face[3]])) { + return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[2]], cos[face[3]]); + } #else - /* cheat - we know first 2 verts are z0.0f and second 2 are z 1.0f */ - /* ... worth looking into */ + /* cheat - we know first 2 verts are z0.0f and second 2 are z 1.0f */ + /* ... worth looking into */ #endif - } - } + } + } - return 1.0f; + return 1.0f; } BLI_INLINE unsigned int layer_bucket_index_from_xy(MaskRasterLayer *layer, const float xy[2]) { - BLI_assert(BLI_rctf_isect_pt_v(&layer->bounds, xy)); + BLI_assert(BLI_rctf_isect_pt_v(&layer->bounds, xy)); - return ( (unsigned int)((xy[0] - layer->bounds.xmin) * layer->buckets_xy_scalar[0])) + - (((unsigned int)((xy[1] - layer->bounds.ymin) * layer->buckets_xy_scalar[1])) * layer->buckets_x); + return ((unsigned int)((xy[0] - layer->bounds.xmin) * layer->buckets_xy_scalar[0])) + + (((unsigned int)((xy[1] - layer->bounds.ymin) * layer->buckets_xy_scalar[1])) * + layer->buckets_x); } static float layer_bucket_depth_from_xy(MaskRasterLayer *layer, const float xy[2]) { - unsigned int index = layer_bucket_index_from_xy(layer, xy); - unsigned int *face_index = layer->buckets_face[index]; - - if (face_index) { - unsigned int (*face_array)[4] = layer->face_array; - float (*cos)[3] = layer->face_coords; - float best_dist = 1.0f; - while (*face_index != TRI_TERMINATOR_ID) { - const float test_dist = maskrasterize_layer_isect(face_array[*face_index], cos, best_dist, xy); - if (test_dist < best_dist) { - best_dist = test_dist; - /* comparing with 0.0f is OK here because triangles are always zero depth */ - if (best_dist == 0.0f) { - /* bail early, we're as close as possible */ - return 0.0f; - } - } - face_index++; - } - return best_dist; - } - else { - return 1.0f; - } + unsigned int index = layer_bucket_index_from_xy(layer, xy); + unsigned int *face_index = layer->buckets_face[index]; + + if (face_index) { + unsigned int(*face_array)[4] = layer->face_array; + float(*cos)[3] = layer->face_coords; + float best_dist = 1.0f; + while (*face_index != TRI_TERMINATOR_ID) { + const float test_dist = maskrasterize_layer_isect( + face_array[*face_index], cos, best_dist, xy); + if (test_dist < best_dist) { + best_dist = test_dist; + /* comparing with 0.0f is OK here because triangles are always zero depth */ + if (best_dist == 0.0f) { + /* bail early, we're as close as possible */ + return 0.0f; + } + } + face_index++; + } + return best_dist; + } + else { + return 1.0f; + } } float BKE_maskrasterize_handle_sample(MaskRasterHandle *mr_handle, const float xy[2]) { - /* can't do this because some layers may invert */ - /* if (BLI_rctf_isect_pt_v(&mr_handle->bounds, xy)) */ - - const unsigned int layers_tot = mr_handle->layers_tot; - unsigned int i; - MaskRasterLayer *layer = mr_handle->layers; - - /* return value */ - float value = 0.0f; - - for (i = 0; i < layers_tot; i++, layer++) { - float value_layer; - - /* also used as signal for unused layer (when render is disabled) */ - if (layer->alpha != 0.0f && BLI_rctf_isect_pt_v(&layer->bounds, xy)) { - value_layer = 1.0f - layer_bucket_depth_from_xy(layer, xy); - - switch (layer->falloff) { - case PROP_SMOOTH: - /* ease - gives less hard lines for dilate/erode feather */ - value_layer = (3.0f * value_layer * value_layer - 2.0f * value_layer * value_layer * value_layer); - break; - case PROP_SPHERE: - value_layer = sqrtf(2.0f * value_layer - value_layer * value_layer); - break; - case PROP_ROOT: - value_layer = sqrtf(value_layer); - break; - case PROP_SHARP: - value_layer = value_layer * value_layer; - break; - case PROP_INVSQUARE: - value_layer = value_layer * (2.0f - value_layer); - break; - case PROP_LIN: - default: - /* nothing */ - break; - } - - if (layer->blend != MASK_BLEND_REPLACE) { - value_layer *= layer->alpha; - } - } - else { - value_layer = 0.0f; - } - - if (layer->blend_flag & MASK_BLENDFLAG_INVERT) { - value_layer = 1.0f - value_layer; - } - - switch (layer->blend) { - case MASK_BLEND_MERGE_ADD: - value += value_layer * (1.0f - value); - break; - case MASK_BLEND_MERGE_SUBTRACT: - value -= value_layer * value; - break; - case MASK_BLEND_ADD: - value += value_layer; - break; - case MASK_BLEND_SUBTRACT: - value -= value_layer; - break; - case MASK_BLEND_LIGHTEN: - value = max_ff(value, value_layer); - break; - case MASK_BLEND_DARKEN: - value = min_ff(value, value_layer); - break; - case MASK_BLEND_MUL: - value *= value_layer; - break; - case MASK_BLEND_REPLACE: - value = (value * (1.0f - layer->alpha)) + (value_layer * layer->alpha); - break; - case MASK_BLEND_DIFFERENCE: - value = fabsf(value - value_layer); - break; - default: /* same as add */ - CLOG_ERROR(&LOG, "unhandled blend type: %d", layer->blend); - BLI_assert(0); - value += value_layer; - break; - } - - /* clamp after applying each layer so we don't get - * issues subtracting after accumulating over 1.0f */ - CLAMP(value, 0.0f, 1.0f); - } - - return value; + /* can't do this because some layers may invert */ + /* if (BLI_rctf_isect_pt_v(&mr_handle->bounds, xy)) */ + + const unsigned int layers_tot = mr_handle->layers_tot; + unsigned int i; + MaskRasterLayer *layer = mr_handle->layers; + + /* return value */ + float value = 0.0f; + + for (i = 0; i < layers_tot; i++, layer++) { + float value_layer; + + /* also used as signal for unused layer (when render is disabled) */ + if (layer->alpha != 0.0f && BLI_rctf_isect_pt_v(&layer->bounds, xy)) { + value_layer = 1.0f - layer_bucket_depth_from_xy(layer, xy); + + switch (layer->falloff) { + case PROP_SMOOTH: + /* ease - gives less hard lines for dilate/erode feather */ + value_layer = (3.0f * value_layer * value_layer - + 2.0f * value_layer * value_layer * value_layer); + break; + case PROP_SPHERE: + value_layer = sqrtf(2.0f * value_layer - value_layer * value_layer); + break; + case PROP_ROOT: + value_layer = sqrtf(value_layer); + break; + case PROP_SHARP: + value_layer = value_layer * value_layer; + break; + case PROP_INVSQUARE: + value_layer = value_layer * (2.0f - value_layer); + break; + case PROP_LIN: + default: + /* nothing */ + break; + } + + if (layer->blend != MASK_BLEND_REPLACE) { + value_layer *= layer->alpha; + } + } + else { + value_layer = 0.0f; + } + + if (layer->blend_flag & MASK_BLENDFLAG_INVERT) { + value_layer = 1.0f - value_layer; + } + + switch (layer->blend) { + case MASK_BLEND_MERGE_ADD: + value += value_layer * (1.0f - value); + break; + case MASK_BLEND_MERGE_SUBTRACT: + value -= value_layer * value; + break; + case MASK_BLEND_ADD: + value += value_layer; + break; + case MASK_BLEND_SUBTRACT: + value -= value_layer; + break; + case MASK_BLEND_LIGHTEN: + value = max_ff(value, value_layer); + break; + case MASK_BLEND_DARKEN: + value = min_ff(value, value_layer); + break; + case MASK_BLEND_MUL: + value *= value_layer; + break; + case MASK_BLEND_REPLACE: + value = (value * (1.0f - layer->alpha)) + (value_layer * layer->alpha); + break; + case MASK_BLEND_DIFFERENCE: + value = fabsf(value - value_layer); + break; + default: /* same as add */ + CLOG_ERROR(&LOG, "unhandled blend type: %d", layer->blend); + BLI_assert(0); + value += value_layer; + break; + } + + /* clamp after applying each layer so we don't get + * issues subtracting after accumulating over 1.0f */ + CLAMP(value, 0.0f, 1.0f); + } + + return value; } - typedef struct MaskRasterizeBufferData { - MaskRasterHandle *mr_handle; - float x_inv, y_inv; - float x_px_ofs, y_px_ofs; - uint width; + MaskRasterHandle *mr_handle; + float x_inv, y_inv; + float x_px_ofs, y_px_ofs; + uint width; - float *buffer; + float *buffer; } MaskRasterizeBufferData; -static void maskrasterize_buffer_cb( - void *__restrict userdata, - const int y, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void maskrasterize_buffer_cb(void *__restrict userdata, + const int y, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - MaskRasterizeBufferData *data = userdata; + MaskRasterizeBufferData *data = userdata; - MaskRasterHandle *mr_handle = data->mr_handle; - float *buffer = data->buffer; + MaskRasterHandle *mr_handle = data->mr_handle; + float *buffer = data->buffer; - const uint width = data->width; - const float x_inv = data->x_inv; - const float x_px_ofs = data->x_px_ofs; + const uint width = data->width; + const float x_inv = data->x_inv; + const float x_px_ofs = data->x_px_ofs; - uint i = (uint)y * width; - float xy[2]; - xy[1] = ((float)y * data->y_inv) + data->y_px_ofs; - for (uint x = 0; x < width; x++, i++) { - xy[0] = ((float)x * x_inv) + x_px_ofs; + uint i = (uint)y * width; + float xy[2]; + xy[1] = ((float)y * data->y_inv) + data->y_px_ofs; + for (uint x = 0; x < width; x++, i++) { + xy[0] = ((float)x * x_inv) + x_px_ofs; - buffer[i] = BKE_maskrasterize_handle_sample(mr_handle, xy); - } + buffer[i] = BKE_maskrasterize_handle_sample(mr_handle, xy); + } } /** * \brief Rasterize a buffer from a single mask (threaded execution). */ void BKE_maskrasterize_buffer(MaskRasterHandle *mr_handle, - const unsigned int width, const unsigned int height, + const unsigned int width, + const unsigned int height, float *buffer) { - const float x_inv = 1.0f / (float)width; - const float y_inv = 1.0f / (float)height; - - MaskRasterizeBufferData data = { - .mr_handle = mr_handle, - .x_inv = x_inv, - .y_inv = y_inv, - .x_px_ofs = x_inv * 0.5f, - .y_px_ofs = y_inv * 0.5f, - .width = width, - .buffer = buffer, - }; - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((size_t)height * width > 10000); - BLI_task_parallel_range(0, (int)height, - &data, - maskrasterize_buffer_cb, - &settings); + const float x_inv = 1.0f / (float)width; + const float y_inv = 1.0f / (float)height; + + MaskRasterizeBufferData data = { + .mr_handle = mr_handle, + .x_inv = x_inv, + .y_inv = y_inv, + .x_px_ofs = x_inv * 0.5f, + .y_px_ofs = y_inv * 0.5f, + .width = width, + .buffer = buffer, + }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((size_t)height * width > 10000); + BLI_task_parallel_range(0, (int)height, &data, maskrasterize_buffer_cb, &settings); } |