From 13254cde8c7ca38af2dcec35efdb9f8f9b3bca46 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 27 Aug 2012 09:44:56 +0000 Subject: Alternate mask spline feather offset calculation method: now there are 2 [Even | Smooth] - Even preserves thickness but can give unsightly loops - Smooth gives nicer shape but can give unsightly feather/spline mismatch for 'S' shapes created by beziers. This is an example where smooth works much nicer. http://www.graphicall.org/ftp/ideasman42/mask_compare.png --- source/blender/blenkernel/intern/mask.c | 19 +-- source/blender/blenkernel/intern/mask_evaluate.c | 170 +++++++++++++++++++++-- source/blender/blenlib/BLI_math_vector.h | 3 + source/blender/blenlib/intern/math_vector.c | 23 +++ source/blender/makesdna/DNA_mask_types.h | 20 ++- source/blender/makesrna/intern/rna_mask.c | 13 ++ 6 files changed, 219 insertions(+), 29 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 5182c52605a..f73fb3879b8 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -1194,17 +1194,6 @@ void BKE_mask_calc_handle_point(MaskSpline *spline, MaskSplinePoint *point) mask_calc_point_handle(point, point_prev, point_next); } -static void enforce_dist_v2_v2fl(float v1[2], const float v2[2], const float dist) -{ - if (!equals_v2v2(v2, v1)) { - float nor[2]; - - sub_v2_v2v2(nor, v1, v2); - normalize_v2(nor); - madd_v2_v2v2fl(v1, v2, nor, dist); - } -} - void BKE_mask_calc_handle_adjacent_interp(MaskSpline *spline, MaskSplinePoint *point, const float u) { /* TODO! - make this interpolate between siblings - not always midpoint! */ @@ -1246,8 +1235,8 @@ void BKE_mask_calc_handle_adjacent_interp(MaskSpline *spline, MaskSplinePoint *p length_average /= (float)length_tot; weight_average /= (float)length_tot; - enforce_dist_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average); - enforce_dist_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average); + dist_ensure_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average); + dist_ensure_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average); point->bezt.weight = weight_average; } } @@ -1279,8 +1268,8 @@ void BKE_mask_calc_handle_point_auto(MaskSpline *spline, MaskSplinePoint *point, /* preserve length by applying it back */ if (do_recalc_length == FALSE) { - enforce_dist_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average); - enforce_dist_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average); + dist_ensure_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average); + dist_ensure_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average); } } diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c index 9d9f1665a7b..065dc38c81e 100644 --- a/source/blender/blenkernel/intern/mask_evaluate.c +++ b/source/blender/blenkernel/intern/mask_evaluate.c @@ -507,15 +507,12 @@ void BKE_mask_spline_feather_collapse_inner_loops(MaskSpline *spline, float (*fe #undef BUCKET_INDEX } -/** - * values align with #BKE_mask_spline_differentiate_with_resolution_ex - * when \a resol arguments match. - */ -float (*BKE_mask_spline_feather_differentiated_points_with_resolution_ex(MaskSpline *spline, - int *tot_feather_point, - const unsigned int resol, - const int do_feather_isect - ))[2] +/** only called from #BKE_mask_spline_feather_differentiated_points_with_resolution_ex() ! */ +static float (*mask_spline_feather_differentiated_points_with_resolution_ex__even(MaskSpline *spline, + int *tot_feather_point, + const unsigned int resol, + const int do_feather_isect + ))[2] { MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline); MaskSplinePoint *point_curr, *point_prev; @@ -583,6 +580,161 @@ float (*BKE_mask_spline_feather_differentiated_points_with_resolution_ex(MaskSpl return feather; } +/** only called from #BKE_mask_spline_feather_differentiated_points_with_resolution_ex() ! */ +static float (*mask_spline_feather_differentiated_points_with_resolution_ex__double(MaskSpline *spline, + int *tot_feather_point, + const unsigned int resol, + const int do_feather_isect + ))[2] +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline); + + MaskSplinePoint *point_curr, *point_prev; + float (*feather)[2], (*fp)[2]; + const int tot = BKE_mask_spline_differentiate_calc_total(spline, resol); + int a; + + if (spline->tot_point <= 1) { + /* nothing to differentiate */ + *tot_feather_point = 0; + return NULL; + } + + /* len+1 because of 'forward_diff_bezier' function */ + *tot_feather_point = tot; + feather = fp = MEM_mallocN((tot + 1) * sizeof(*feather), "mask spline vets"); + + a = spline->tot_point - 1; + if (spline->flag & MASK_SPLINE_CYCLIC) + a++; + + point_prev = points_array; + point_curr = point_prev + 1; + + while (a--) { + BezTriple local_prevbezt; + BezTriple local_bezt; + float point_prev_n[2], point_curr_n[2], tvec[2]; + float weight_prev, weight_curr; + float len_base, len_feather, len_scalar; + + BezTriple *bezt_prev; + BezTriple *bezt_curr; + int j; + + if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC)) + point_curr = points_array; + + bezt_prev = &point_prev->bezt; + bezt_curr = &point_curr->bezt; + + /* modified copy for feather */ + local_prevbezt = *bezt_prev; + local_bezt = *bezt_curr; + + bezt_prev = &local_prevbezt; + bezt_curr = &local_bezt; + + /* calc the normals */ + sub_v2_v2v2(tvec, bezt_prev->vec[1], bezt_prev->vec[0]); + normalize_v2(tvec); + point_prev_n[0] = -tvec[1]; + point_prev_n[1] = tvec[0]; + + sub_v2_v2v2(tvec, bezt_curr->vec[1], bezt_curr->vec[0]); + normalize_v2(tvec); + point_curr_n[0] = -tvec[1]; + point_curr_n[1] = tvec[0]; + + weight_prev = bezt_prev->weight; + weight_curr = bezt_curr->weight; + + mul_v2_fl(point_prev_n, weight_prev); + mul_v2_fl(point_curr_n, weight_curr); + + /* before we transform verts */ + len_base = len_v2v2(bezt_prev->vec[1], bezt_curr->vec[1]); + + // add_v2_v2(bezt_prev->vec[0], point_prev_n); // not needed + add_v2_v2(bezt_prev->vec[1], point_prev_n); + add_v2_v2(bezt_prev->vec[2], point_prev_n); + + add_v2_v2(bezt_curr->vec[0], point_curr_n); + add_v2_v2(bezt_curr->vec[1], point_curr_n); + // add_v2_v2(bezt_curr->vec[2], point_curr_n); // not needed + + len_feather = len_v2v2(bezt_prev->vec[1], bezt_curr->vec[1]); + + /* scale by chane in length */ + len_scalar = len_feather / len_base; + dist_ensure_v2_v2fl(bezt_prev->vec[2], bezt_prev->vec[1], len_scalar * len_v2v2(bezt_prev->vec[2], bezt_prev->vec[1])); + dist_ensure_v2_v2fl(bezt_curr->vec[0], bezt_curr->vec[1], len_scalar * len_v2v2(bezt_curr->vec[0], bezt_curr->vec[1])); + + + for (j = 0; j < 2; j++) { + BKE_curve_forward_diff_bezier(bezt_prev->vec[1][j], bezt_prev->vec[2][j], + bezt_curr->vec[0][j], bezt_curr->vec[1][j], + &(*fp)[j], resol, 2 * sizeof(float)); + } + + + /* scale by the uw's */ + if (point_prev->tot_uw) { + for (j = 0; j < resol; j++, fp++) { + float u = (float) j / resol; + float weight_uw, weight_scalar; + float co[2]; + + /* TODO - these calls all calculate similar things + * could be unified for some speed */ + BKE_mask_point_segment_co(spline, point_prev, u, co); + + weight_uw = BKE_mask_point_weight(spline, point_prev, u); + weight_scalar = BKE_mask_point_weight_scalar(spline, point_prev, u); + + dist_ensure_v2_v2fl(*fp, co, len_v2v2(*fp, co) * (weight_uw / weight_scalar)); + } + } + else { + fp += resol; + } + + if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC) == 0) { + copy_v2_v2(*fp, bezt_curr->vec[1]); + } + + point_prev = point_curr; + point_curr++; + } + + if ((spline->flag & MASK_SPLINE_NOINTERSECT) && do_feather_isect) { + BKE_mask_spline_feather_collapse_inner_loops(spline, feather, tot); + } + + return feather; +} + +/** + * values align with #BKE_mask_spline_differentiate_with_resolution_ex + * when \a resol arguments match. + */ +float (*BKE_mask_spline_feather_differentiated_points_with_resolution_ex(MaskSpline *spline, + int *tot_feather_point, + const unsigned int resol, + const int do_feather_isect + ))[2] +{ + switch (spline->offset_mode) { + case MASK_SPLINE_OFFSET_EVEN: + return mask_spline_feather_differentiated_points_with_resolution_ex__even(spline, tot_feather_point, resol, do_feather_isect); + break; + case MASK_SPLINE_OFFSET_SMOOTH: + default: + return mask_spline_feather_differentiated_points_with_resolution_ex__double(spline, tot_feather_point, resol, do_feather_isect); + break; + } +} + float (*BKE_mask_spline_feather_differentiated_points_with_resolution(MaskSpline *spline, int width, int height, int *tot_feather_point, const int do_feather_isect))[2] { diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 8499a7f219c..eef8c9daaef 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -220,6 +220,9 @@ MINLINE void normal_float_to_short_v3(short r[3], const float n[3]); void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]); +void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist); +void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist); + /***************************** Array Functions *******************************/ /* attempted to follow fixed length vertex functions. names could be improved*/ double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size); diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index 5cda1c0b81f..4196bab0474 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -451,6 +451,29 @@ void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]) if (max[2] < vec[2]) max[2] = vec[2]; } +/** ensure \a v1 is \a dist from \a v2 */ +void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist) +{ + if (!equals_v3v3(v2, v1)) { + float nor[3]; + + sub_v3_v3v3(nor, v1, v2); + normalize_v3(nor); + madd_v3_v3v3fl(v1, v2, nor, dist); + } +} + +void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist) +{ + if (!equals_v2v2(v2, v1)) { + float nor[2]; + + sub_v2_v2v2(nor, v1, v2); + normalize_v2(nor); + madd_v2_v2v2fl(v1, v2, nor, dist); + } +} + /***************************** Array Functions *******************************/ double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size) diff --git a/source/blender/makesdna/DNA_mask_types.h b/source/blender/makesdna/DNA_mask_types.h index 6c7f7aa2471..bf388d8c018 100644 --- a/source/blender/makesdna/DNA_mask_types.h +++ b/source/blender/makesdna/DNA_mask_types.h @@ -82,13 +82,14 @@ typedef struct MaskSplinePoint { typedef struct MaskSpline { struct MaskSpline *next, *prev; - int flag; /* defferent spline flag (closed, ...) */ + short flag; /* defferent spline flag (closed, ...) */ + char offset_mode; /* feather offset method */ + char weight_interp; /* weight interpolation */ + int tot_point; /* total number of points */ MaskSplinePoint *points; /* points which defines spline itself */ MaskParent parent; /* parenting information of the whole spline */ - int weight_interp, pad; /* weight interpolation */ - MaskSplinePoint *points_deform; /* deformed copy of 'points' BezTriple data - not saved */ } MaskSpline; @@ -146,8 +147,17 @@ enum { }; /* MaskSpline->weight_interp */ -#define MASK_SPLINE_INTERP_LINEAR 1 -#define MASK_SPLINE_INTERP_EASE 2 +enum { + MASK_SPLINE_INTERP_LINEAR = 1, + MASK_SPLINE_INTERP_EASE = 2 +}; + +/* MaskSpline->offset_mode */ +enum { + MASK_SPLINE_OFFSET_EVEN = 0, + MASK_SPLINE_OFFSET_SMOOTH = 1 +}; + /* ob->restrictflag */ #define MASK_RESTRICT_VIEW 1 diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c index a6571a2db4f..719baed8edb 100644 --- a/source/blender/makesrna/intern/rna_mask.c +++ b/source/blender/makesrna/intern/rna_mask.c @@ -540,6 +540,12 @@ static void rna_def_maskSpline(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem spline_offset_mode_items[] = { + {MASK_SPLINE_OFFSET_EVEN, "EVEN", 0, "Even", "Calculate even feather offset"}, + {MASK_SPLINE_OFFSET_SMOOTH, "SMOOTH", 0, "Smooth", "Calculate feather offset as a second curve"}, + {0, NULL, 0, NULL, NULL} + }; + StructRNA *srna; PropertyRNA *prop; @@ -548,6 +554,13 @@ static void rna_def_maskSpline(BlenderRNA *brna) srna = RNA_def_struct(brna, "MaskSpline", NULL); RNA_def_struct_ui_text(srna, "Mask spline", "Single spline used for defining mask shape"); + /* offset mode */ + prop = RNA_def_property(srna, "offset_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "offset_mode"); + RNA_def_property_enum_items(prop, spline_offset_mode_items); + RNA_def_property_ui_text(prop, "Feather Offset", "The method used for calculating the feather offset"); + RNA_def_property_update(prop, 0, "rna_Mask_update_data"); + /* weight interpolation */ prop = RNA_def_property(srna, "weight_interpolation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "weight_interp"); -- cgit v1.2.3