diff options
-rw-r--r-- | release/scripts/startup/bl_ui/properties_mask_common.py | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_mask.h | 34 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/curve.c | 10 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mask.c | 185 | ||||
-rw-r--r-- | source/blender/editors/interface/resources.c | 65 | ||||
-rw-r--r-- | source/blender/editors/mask/mask_add.c | 148 | ||||
-rw-r--r-- | source/blender/editors/mask/mask_draw.c | 192 | ||||
-rw-r--r-- | source/blender/editors/mask/mask_edit.c | 4 | ||||
-rw-r--r-- | source/blender/editors/mask/mask_intern.h | 2 | ||||
-rw-r--r-- | source/blender/editors/mask/mask_ops.c | 229 | ||||
-rw-r--r-- | source/blender/editors/mask/mask_select.c | 30 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_conversions.c | 195 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_curve_types.h | 3 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_mask.c | 96 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_userdef.c | 48 |
15 files changed, 868 insertions, 376 deletions
diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py index cd659e1e5fe..eef7b00f0be 100644 --- a/release/scripts/startup/bl_ui/properties_mask_common.py +++ b/release/scripts/startup/bl_ui/properties_mask_common.py @@ -173,9 +173,6 @@ class MASK_PT_point(): parent = point.parent col = layout.column() - col.prop(point, "handle_type") - - col = layout.column() # Currently only parenting yo movie clip is allowed, so do not # ver-oplicate things for now and use single template_ID #col.template_any_ID(parent, "id", "id_type", text="") diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index 691afaf8f16..5dd0b14be63 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -47,6 +47,20 @@ struct MovieClip; struct MovieClipUser; struct Scene; +/* mask_ops.c */ +typedef enum { + MASK_WHICH_HANDLE_NONE = 0, + MASK_WHICH_HANDLE_STICK = 1, + MASK_WHICH_HANDLE_LEFT = 2, + MASK_WHICH_HANDLE_RIGHT = 3, + MASK_WHICH_HANDLE_BOTH = 4, +} eMaskWhichHandle; + +typedef enum { + MASK_HANDLE_MODE_STICK = 1, + MASK_HANDLE_MODE_INDIVIDUAL_HANDLES = 2, +} eMaskhandleMode; + struct MaskSplinePoint *BKE_mask_spline_point_array(struct MaskSpline *spline); struct MaskSplinePoint *BKE_mask_spline_point_array_from_point(struct MaskSpline *spline, struct MaskSplinePoint *point_ref); @@ -87,9 +101,9 @@ float BKE_mask_spline_project_co(struct MaskSpline *spline, struct MaskSplinePoi float start_u, const float co[2], const eMaskSign sign); /* point */ -bool BKE_mask_point_has_handle(struct MaskSplinePoint *point); -void BKE_mask_point_handle(struct MaskSplinePoint *point, float handle[2]); -void BKE_mask_point_set_handle(struct MaskSplinePoint *point, float loc[2], bool keep_direction, +eMaskhandleMode BKE_mask_point_handles_mode_get(struct MaskSplinePoint *point); +void BKE_mask_point_handle(struct MaskSplinePoint *point, eMaskWhichHandle which_handle, float handle[2]); +void BKE_mask_point_set_handle(struct MaskSplinePoint *point, eMaskWhichHandle which_handle, float loc[2], bool keep_direction, float orig_handle[2], float orig_vec[3][3]); void BKE_mask_point_segment_co(struct MaskSpline *spline, struct MaskSplinePoint *point, float u, float co[2]); @@ -101,7 +115,7 @@ struct MaskSplinePointUW *BKE_mask_point_sort_uw(struct MaskSplinePoint *point, void BKE_mask_point_add_uw(struct MaskSplinePoint *point, float u, float w); void BKE_mask_point_select_set(struct MaskSplinePoint *point, const bool do_select); -void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point, const bool do_select); +void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point, const eMaskWhichHandle which_handle, const bool do_select); /* general */ struct Mask *BKE_mask_new(struct Main *bmain, const char *name); @@ -176,16 +190,18 @@ void BKE_mask_clipboard_paste_to_layer(struct Main *bmain, struct MaskLayer *mas #define MASKPOINT_ISSEL_ANY(p) ( ((p)->bezt.f1 | (p)->bezt.f2 | (p)->bezt.f3) & SELECT) #define MASKPOINT_ISSEL_KNOT(p) ( (p)->bezt.f2 & SELECT) -#define MASKPOINT_ISSEL_HANDLE_ONLY(p) ( (((p)->bezt.f1 | (p)->bezt.f3) & SELECT) && (((p)->bezt.f2 & SELECT) == 0) ) -#define MASKPOINT_ISSEL_HANDLE(p) ( (((p)->bezt.f1 | (p)->bezt.f3) & SELECT) ) + +#define MASKPOINT_ISSEL_HANDLE(point, which_handle) \ + ((which_handle == MASK_WHICH_HANDLE_STICK) ? \ + ((((point)->bezt.f1 | (point)->bezt.f3) & SELECT)) : \ + ((which_handle == MASK_WHICH_HANDLE_LEFT) ? \ + ((point)->bezt.f1 & SELECT) : \ + ((point)->bezt.f3 & SELECT))) #define MASKPOINT_SEL_ALL(p) { (p)->bezt.f1 |= SELECT; (p)->bezt.f2 |= SELECT; (p)->bezt.f3 |= SELECT; } (void)0 #define MASKPOINT_DESEL_ALL(p) { (p)->bezt.f1 &= ~SELECT; (p)->bezt.f2 &= ~SELECT; (p)->bezt.f3 &= ~SELECT; } (void)0 #define MASKPOINT_INVSEL_ALL(p) { (p)->bezt.f1 ^= SELECT; (p)->bezt.f2 ^= SELECT; (p)->bezt.f3 ^= SELECT; } (void)0 -#define MASKPOINT_SEL_HANDLE(p) { (p)->bezt.f1 |= SELECT; (p)->bezt.f3 |= SELECT; } (void)0 -#define MASKPOINT_DESEL_HANDLE(p) { (p)->bezt.f1 &= ~SELECT; (p)->bezt.f3 &= ~SELECT; } (void)0 - #define MASK_RESOL_MAX 128 diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 44c9bc9ebbe..0ce2953a2e3 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -3080,7 +3080,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n madd_v3_v3v3fl(p2_h2, p2, dvec_b, 1.0f / 3.0f); } - if (skip_align || !ELEM(HD_ALIGN, bezt->h1, bezt->h2)) { + if (skip_align || (!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) { /* handles need to be updated during animation and applying stuff like hooks, * but in such situations it's quite difficult to distinguish in which order * align handles should be aligned so skip them for now */ @@ -3095,7 +3095,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n len_b = 1.0f; if (bezt->f1 & SELECT) { /* order of calculation */ - if (bezt->h2 == HD_ALIGN) { /* aligned */ + if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */ if (len_a > eps) { len = len_b / len_a; p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]); @@ -3103,7 +3103,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n p2_h2[2] = p2[2] + len * (p2[2] - p2_h1[2]); } } - if (bezt->h1 == HD_ALIGN) { + if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { if (len_b > eps) { len = len_a / len_b; p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]); @@ -3113,7 +3113,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n } } else { - if (bezt->h1 == HD_ALIGN) { + if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { if (len_b > eps) { len = len_a / len_b; p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]); @@ -3121,7 +3121,7 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n p2_h1[2] = p2[2] + len * (p2[2] - p2_h2[2]); } } - if (bezt->h2 == HD_ALIGN) { /* aligned */ + if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */ if (len_a > eps) { len = len_b / len_a; p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]); diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index d08b7316e61..8ea035e3249 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -435,58 +435,87 @@ float BKE_mask_spline_project_co(MaskSpline *spline, MaskSplinePoint *point, /* point */ -bool BKE_mask_point_has_handle(MaskSplinePoint *point) +eMaskhandleMode BKE_mask_point_handles_mode_get(MaskSplinePoint *point) { BezTriple *bezt = &point->bezt; - return bezt->h1 == HD_ALIGN; + if (bezt->h1 == bezt->h2 && bezt->h1 == HD_ALIGN) { + return MASK_HANDLE_MODE_STICK; + } + + return MASK_HANDLE_MODE_INDIVIDUAL_HANDLES; } -void BKE_mask_point_handle(MaskSplinePoint *point, float handle[2]) +void BKE_mask_point_handle(MaskSplinePoint *point, eMaskWhichHandle which_handle, float handle[2]) { - float vec[2]; + BezTriple *bezt = &point->bezt; + + if (which_handle == MASK_WHICH_HANDLE_STICK) { + float vec[2]; - sub_v2_v2v2(vec, point->bezt.vec[0], point->bezt.vec[1]); + sub_v2_v2v2(vec, bezt->vec[0], bezt->vec[1]); - handle[0] = (point->bezt.vec[1][0] + vec[1]); - handle[1] = (point->bezt.vec[1][1] - vec[0]); + handle[0] = (bezt->vec[1][0] + vec[1]); + handle[1] = (bezt->vec[1][1] - vec[0]); + } + else if (which_handle == MASK_WHICH_HANDLE_LEFT) { + copy_v2_v2(handle, bezt->vec[0]); + } + else if (which_handle == MASK_WHICH_HANDLE_RIGHT) { + copy_v2_v2(handle, bezt->vec[2]); + } + else { + BLI_assert(!"Unknown handle passed to BKE_mask_point_handle"); + } } -void BKE_mask_point_set_handle(MaskSplinePoint *point, float loc[2], bool keep_direction, +void BKE_mask_point_set_handle(MaskSplinePoint *point, eMaskWhichHandle which_handle, + float loc[2], bool keep_direction, float orig_handle[2], float orig_vec[3][3]) { BezTriple *bezt = &point->bezt; - float v1[2], v2[2], vec[2]; - if (keep_direction) { - sub_v2_v2v2(v1, loc, orig_vec[1]); - sub_v2_v2v2(v2, orig_handle, orig_vec[1]); + if (which_handle == MASK_WHICH_HANDLE_STICK) { + float v1[2], v2[2], vec[2]; + if (keep_direction) { + sub_v2_v2v2(v1, loc, orig_vec[1]); + sub_v2_v2v2(v2, orig_handle, orig_vec[1]); - project_v2_v2v2(vec, v1, v2); + project_v2_v2v2(vec, v1, v2); - if (dot_v2v2(v2, vec) > 0) { - float len = len_v2(vec); + if (dot_v2v2(v2, vec) > 0) { + float len = len_v2(vec); - sub_v2_v2v2(v1, orig_vec[0], orig_vec[1]); + sub_v2_v2v2(v1, orig_vec[0], orig_vec[1]); - mul_v2_fl(v1, len / len_v2(v1)); + mul_v2_fl(v1, len / len_v2(v1)); - add_v2_v2v2(bezt->vec[0], bezt->vec[1], v1); - sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v1); + add_v2_v2v2(bezt->vec[0], bezt->vec[1], v1); + sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v1); + } + else { + copy_v3_v3(bezt->vec[0], bezt->vec[1]); + copy_v3_v3(bezt->vec[2], bezt->vec[1]); + } } else { - copy_v3_v3(bezt->vec[0], bezt->vec[1]); - copy_v3_v3(bezt->vec[2], bezt->vec[1]); + sub_v2_v2v2(v1, loc, bezt->vec[1]); + + v2[0] = -v1[1]; + v2[1] = v1[0]; + + add_v2_v2v2(bezt->vec[0], bezt->vec[1], v2); + sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v2); } } + else if (which_handle == MASK_WHICH_HANDLE_LEFT) { + copy_v2_v2(bezt->vec[0], loc); + } + else if (which_handle == MASK_WHICH_HANDLE_RIGHT) { + copy_v2_v2(bezt->vec[2], loc); + } else { - sub_v2_v2v2(v1, loc, bezt->vec[1]); - - v2[0] = -v1[1]; - v2[1] = v1[0]; - - add_v2_v2v2(bezt->vec[0], bezt->vec[1], v2); - sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v2); + BLI_assert(!"unknown handle passed to BKE_mask_point_set_handle"); } } @@ -514,36 +543,68 @@ void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float interp_v2_v2v2(co, r0, r1, u); } +BLI_INLINE void orthogonal_direction_get(float vec[2], float result[2]) +{ + result[0] = -vec[1]; + result[1] = vec[0]; + normalize_v2(result); +} + +/* TODO(sergey): This function will re-calculate loads of stuff again and again + * when differentiating feather points. This might be easily cached + * in the callee function for this case. + */ void BKE_mask_point_normal(MaskSpline *spline, MaskSplinePoint *point, float u, float n[2]) { - MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point); - BezTriple *bezt = &point->bezt, *bezt_next; - float q0[2], q1[2], q2[2], r0[2], r1[2], vec[2]; + MaskSplinePoint *point_prev, *point_next; - bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point); + /* TODO(sergey): This actually depends on a resolution. */ + const float du = 0.05f; - if (!bezt_next) { - BKE_mask_point_handle(point, vec); + BKE_mask_get_handle_point_adjacent(spline, point, &point_prev, &point_next); - sub_v2_v2v2(n, vec, bezt->vec[1]); - normalize_v2(n); - return; + if (u - du < 0.0f && point_prev == NULL) { + float co[2], dir[2]; + BKE_mask_point_segment_co(spline, point, u + du, co); + sub_v2_v2v2(dir, co, point->bezt.vec[1]); + orthogonal_direction_get(dir, n); + } + else if (u + du > 1.0f && point_next == NULL) { + float co[2], dir[2]; + BKE_mask_point_segment_co(spline, point, u - du, co); + sub_v2_v2v2(dir, point->bezt.vec[1], co); + orthogonal_direction_get(dir, n); } + else { + float prev_co[2], next_co[2], co[2]; + float dir1[2], dir2[2], dir[2]; - interp_v2_v2v2(q0, bezt->vec[1], bezt->vec[2], u); - interp_v2_v2v2(q1, bezt->vec[2], bezt_next->vec[0], u); - interp_v2_v2v2(q2, bezt_next->vec[0], bezt_next->vec[1], u); + if (u - du < 0.0f) { + BKE_mask_point_segment_co(spline, point_prev, 1.0f + (u - du), prev_co); + } + else { + BKE_mask_point_segment_co(spline, point, u - du, prev_co); + } - interp_v2_v2v2(r0, q0, q1, u); - interp_v2_v2v2(r1, q1, q2, u); + BKE_mask_point_segment_co(spline, point, u, co); + + if (u + du > 1.0f) { + BKE_mask_point_segment_co(spline, point_next, u + du - 1.0f, next_co); + } + else { + BKE_mask_point_segment_co(spline, point, u + du, next_co); + } - sub_v2_v2v2(vec, r1, r0); + sub_v2_v2v2(dir1, co, prev_co); + sub_v2_v2v2(dir2, next_co, co); - n[0] = -vec[1]; - n[1] = vec[0]; + normalize_v2(dir1); + normalize_v2(dir2); + add_v2_v2v2(dir, dir1, dir2); - normalize_v2(n); + orthogonal_direction_get(dir, n); + } } static float mask_point_interp_weight(BezTriple *bezt, BezTriple *bezt_next, const float u) @@ -693,13 +754,37 @@ void BKE_mask_point_select_set(MaskSplinePoint *point, const bool do_select) } } -void BKE_mask_point_select_set_handle(MaskSplinePoint *point, const bool do_select) +void BKE_mask_point_select_set_handle(MaskSplinePoint *point, const eMaskWhichHandle which_handle, const bool do_select) { if (do_select) { - MASKPOINT_SEL_HANDLE(point); + if (ELEM(which_handle, MASK_WHICH_HANDLE_STICK, MASK_WHICH_HANDLE_BOTH)) { + point->bezt.f1 |= SELECT; + point->bezt.f3 |= SELECT; + } + else if (which_handle == MASK_WHICH_HANDLE_LEFT) { + point->bezt.f1 |= SELECT; + } + else if (which_handle == MASK_WHICH_HANDLE_RIGHT) { + point->bezt.f3 |= SELECT; + } + else { + BLI_assert(!"Wrong which_handle passed to BKE_mask_point_select_set_handle"); + } } else { - MASKPOINT_DESEL_HANDLE(point); + if (ELEM(which_handle, MASK_WHICH_HANDLE_STICK, MASK_WHICH_HANDLE_BOTH)) { + point->bezt.f1 &= ~SELECT; + point->bezt.f3 &= ~SELECT; + } + else if (which_handle == MASK_WHICH_HANDLE_LEFT) { + point->bezt.f1 &= ~SELECT; + } + else if (which_handle == MASK_WHICH_HANDLE_RIGHT) { + point->bezt.f3 &= ~SELECT; + } + else { + BLI_assert(!"Wrong which_handle passed to BKE_mask_point_select_set_handle"); + } } } @@ -1170,7 +1255,7 @@ static void mask_calc_point_handle(MaskSplinePoint *point, MaskSplinePoint *poin else if (handle_type == HD_AUTO) { BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, 0); } - else if (handle_type == HD_ALIGN) { + else if (handle_type == HD_ALIGN || handle_type == HD_ALIGN_DOUBLESIDE) { float v1[3], v2[3]; float vec[3], h[3]; diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index a112106620f..8e53f9d2332 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -763,6 +763,18 @@ static void ui_theme_init_new(bTheme *btheme) } } +static void ui_theme_space_init_handles_color(ThemeSpace *theme_space) +{ + rgba_char_args_set(theme_space->handle_free, 0, 0, 0, 255); + rgba_char_args_set(theme_space->handle_auto, 0x90, 0x90, 0x00, 255); + rgba_char_args_set(theme_space->handle_vect, 0x40, 0x90, 0x30, 255); + rgba_char_args_set(theme_space->handle_align, 0x80, 0x30, 0x60, 255); + rgba_char_args_set(theme_space->handle_sel_free, 0, 0, 0, 255); + rgba_char_args_set(theme_space->handle_sel_auto, 0xf0, 0xff, 0x40, 255); + rgba_char_args_set(theme_space->handle_sel_vect, 0x40, 0xc0, 0x30, 255); + rgba_char_args_set(theme_space->handle_sel_align, 0xf0, 0x90, 0xa0, 255); + rgba_char_args_set(theme_space->act_spline, 0xdb, 0x25, 0x12, 255); +} /* initialize default theme * Note: when you add new colors, created & saved themes need initialized @@ -873,14 +885,7 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tv3d.nurb_sel_uline, 0xf0, 0xff, 0x40, 255); rgba_char_args_set(btheme->tv3d.nurb_sel_vline, 0xf0, 0x90, 0xa0, 255); - rgba_char_args_set(btheme->tv3d.handle_free, 0, 0, 0, 255); - rgba_char_args_set(btheme->tv3d.handle_auto, 0x90, 0x90, 0x00, 255); - rgba_char_args_set(btheme->tv3d.handle_vect, 0x40, 0x90, 0x30, 255); - rgba_char_args_set(btheme->tv3d.handle_align, 0x80, 0x30, 0x60, 255); - rgba_char_args_set(btheme->tv3d.handle_sel_free, 0, 0, 0, 255); - rgba_char_args_set(btheme->tv3d.handle_sel_auto, 0xf0, 0xff, 0x40, 255); - rgba_char_args_set(btheme->tv3d.handle_sel_vect, 0x40, 0xc0, 0x30, 255); - rgba_char_args_set(btheme->tv3d.handle_sel_align, 0xf0, 0x90, 0xa0, 255); + ui_theme_space_init_handles_color(&btheme->tv3d); rgba_char_args_set(btheme->tv3d.act_spline, 0xdb, 0x25, 0x12, 255); rgba_char_args_set(btheme->tv3d.lastsel_point, 0xff, 0xff, 0xff, 255); @@ -1023,6 +1028,9 @@ void ui_theme_init_default(void) rgba_char_args_test_set(btheme->tima.uv_others, 96, 96, 96, 255); rgba_char_args_test_set(btheme->tima.uv_shadow, 112, 112, 112, 255); + ui_theme_space_init_handles_color(&btheme->tima); + btheme->tima.handle_vertex_size = 5; + /* space text */ btheme->text = btheme->tv3d; rgba_char_args_set(btheme->text.back, 153, 153, 153, 255); @@ -1125,7 +1133,8 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tclip.list, 0x66, 0x66, 0x66, 0xff); rgba_char_args_set(btheme->tclip.strip, 0x0c, 0x0a, 0x0a, 0x80); rgba_char_args_set(btheme->tclip.strip_select, 0xff, 0x8c, 0x00, 0xff); - btheme->tclip.handle_vertex_size = 4; + btheme->tclip.handle_vertex_size = 5; + ui_theme_space_init_handles_color(&btheme->tclip); } void ui_style_init_default(void) @@ -1885,27 +1894,9 @@ void init_userdef_do_versions(void) /* init new curve colors */ for (btheme = U.themes.first; btheme; btheme = btheme->next) { - /* init colors used for handles in 3D-View */ - rgba_char_args_set(btheme->tv3d.handle_free, 0, 0, 0, 255); - rgba_char_args_set(btheme->tv3d.handle_auto, 0x90, 0x90, 0x00, 255); - rgba_char_args_set(btheme->tv3d.handle_vect, 0x40, 0x90, 0x30, 255); - rgba_char_args_set(btheme->tv3d.handle_align, 0x80, 0x30, 0x60, 255); - rgba_char_args_set(btheme->tv3d.handle_sel_free, 0, 0, 0, 255); - rgba_char_args_set(btheme->tv3d.handle_sel_auto, 0xf0, 0xff, 0x40, 255); - rgba_char_args_set(btheme->tv3d.handle_sel_vect, 0x40, 0xc0, 0x30, 255); - rgba_char_args_set(btheme->tv3d.handle_sel_align, 0xf0, 0x90, 0xa0, 255); - rgba_char_args_set(btheme->tv3d.act_spline, 0xdb, 0x25, 0x12, 255); - - /* same colors again for Graph Editor... */ - rgba_char_args_set(btheme->tipo.handle_free, 0, 0, 0, 255); - rgba_char_args_set(btheme->tipo.handle_auto, 0x90, 0x90, 0x00, 255); - rgba_char_args_set(btheme->tipo.handle_vect, 0x40, 0x90, 0x30, 255); - rgba_char_args_set(btheme->tipo.handle_align, 0x80, 0x30, 0x60, 255); - rgba_char_args_set(btheme->tipo.handle_sel_free, 0, 0, 0, 255); - rgba_char_args_set(btheme->tipo.handle_sel_auto, 0xf0, 0xff, 0x40, 255); - rgba_char_args_set(btheme->tipo.handle_sel_vect, 0x40, 0xc0, 0x30, 255); - rgba_char_args_set(btheme->tipo.handle_sel_align, 0xf0, 0x90, 0xa0, 255); - + ui_theme_space_init_handles_color(&btheme->tv3d); + ui_theme_space_init_handles_color(&btheme->tipo); + /* edge crease */ rgba_char_args_set_fl(btheme->tv3d.edge_crease, 0.8, 0, 0.6, 1.0); } @@ -2010,7 +2001,7 @@ void init_userdef_do_versions(void) rgba_char_args_set(btheme->tclip.cframe, 0x60, 0xc0, 0x40, 255); rgba_char_args_set(btheme->tclip.handle_vertex, 0x00, 0x00, 0x00, 0xff); rgba_char_args_set(btheme->tclip.handle_vertex_select, 0xff, 0xff, 0, 0xff); - btheme->tclip.handle_vertex_size = 4; + btheme->tclip.handle_vertex_size = 5; } /* auto-clamped handles -> based on auto */ @@ -2423,7 +2414,17 @@ void init_userdef_do_versions(void) } } } - + + { + bTheme *btheme; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + ui_theme_space_init_handles_color(&btheme->tclip); + ui_theme_space_init_handles_color(&btheme->tima); + btheme->tima.handle_vertex_size = 5; + btheme->tclip.handle_vertex_size = 5; + } + } + if (U.pixelsize == 0.0f) U.pixelsize = 1.0f; diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index 7fa41c361bb..2e1d5221b56 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -182,15 +182,13 @@ static int find_nearest_diff_point(const bContext *C, Mask *mask, const float no /******************** add vertex *********************/ static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *new_point, - const float point_co[2], const float tangent[2], const float u, - MaskSplinePoint *reference_point, const short reference_adjacent, - const float view_zoom) + const float point_co[2], const float u, + MaskSplinePoint *reference_point, const short reference_adjacent) { MaskSplinePoint *prev_point = NULL; MaskSplinePoint *next_point = NULL; BezTriple *bezt; float co[3]; - const float len = 10.0; /* default length of handle in pixel space */ copy_v2_v2(co, point_co); co[2] = 0.0f; @@ -201,7 +199,41 @@ static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint * bezt->h1 = bezt->h2 = HD_ALIGN; if (reference_point) { - bezt->h1 = bezt->h2 = MAX2(reference_point->bezt.h2, reference_point->bezt.h1); + if (reference_point->bezt.h1 == HD_VECT && reference_point->bezt.h2 == HD_VECT) { + /* If the reference point is sharp try using some smooth point as reference + * for handles. + */ + int point_index = reference_point - spline->points; + int delta = new_point == spline->points ? 1 : -1; + int i = 0; + for (i = 0; i < spline->tot_point - 1; ++i) { + MaskSplinePoint *current_point; + + point_index += delta; + if (point_index == -1 || point_index >= spline->tot_point) { + if (spline->flag & MASK_SPLINE_CYCLIC) { + if (point_index == -1) { + point_index = spline->tot_point - 1; + } + else if (point_index >= spline->tot_point) { + point_index = 0; + } + } + else { + break; + } + } + + current_point = &spline->points[point_index]; + if (current_point->bezt.h1 != HD_VECT || current_point->bezt.h2 != HD_VECT) { + bezt->h1 = bezt->h2 = MAX2(current_point->bezt.h2, current_point->bezt.h1); + break; + } + } + } + else { + bezt->h1 = bezt->h2 = MAX2(reference_point->bezt.h2, reference_point->bezt.h1); + } } else if (reference_adjacent) { if (spline->tot_point != 1) { @@ -219,83 +251,11 @@ static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint * copy_v3_v3(bezt->vec[1], co); copy_v3_v3(bezt->vec[2], co); - /* initial offset for handles */ - if (spline->tot_point == 1) { - /* first point of splien is aligned horizontally */ - bezt->vec[0][0] -= len * view_zoom; - bezt->vec[2][0] += len * view_zoom; - } - else if (tangent) { - float vec[2]; - - copy_v2_v2(vec, tangent); - - mul_v2_fl(vec, len); - - sub_v2_v2(bezt->vec[0], vec); - add_v2_v2(bezt->vec[2], vec); - - if (reference_adjacent) { - BKE_mask_calc_handle_adjacent_interp(spline, new_point, u); - } - } - else { - - /* calculating auto handles works much nicer */ -#if 0 - /* next points are aligning in the direction of previous/next point */ - MaskSplinePoint *point; - float v1[2], v2[2], vec[2]; - float dir = 1.0f; - - if (new_point == spline->points) { - point = new_point + 1; - dir = -1.0f; - } - else - point = new_point - 1; - - if (spline->tot_point < 3) { - v1[0] = point->bezt.vec[1][0] * width; - v1[1] = point->bezt.vec[1][1] * height; - - v2[0] = new_point->bezt.vec[1][0] * width; - v2[1] = new_point->bezt.vec[1][1] * height; - } - else { - if (new_point == spline->points) { - v1[0] = spline->points[1].bezt.vec[1][0] * width; - v1[1] = spline->points[1].bezt.vec[1][1] * height; - - v2[0] = spline->points[spline->tot_point - 1].bezt.vec[1][0] * width; - v2[1] = spline->points[spline->tot_point - 1].bezt.vec[1][1] * height; - } - else { - v1[0] = spline->points[0].bezt.vec[1][0] * width; - v1[1] = spline->points[0].bezt.vec[1][1] * height; - - v2[0] = spline->points[spline->tot_point - 2].bezt.vec[1][0] * width; - v2[1] = spline->points[spline->tot_point - 2].bezt.vec[1][1] * height; - } - } - - sub_v2_v2v2(vec, v1, v2); - mul_v2_fl(vec, len * dir / len_v2(vec)); - - vec[0] /= width; - vec[1] /= height; - - add_v2_v2(bezt->vec[0], vec); - sub_v2_v2(bezt->vec[2], vec); -#else - BKE_mask_calc_handle_point_auto(spline, new_point, TRUE); + BKE_mask_parent_init(&new_point->parent); + if (spline->tot_point != 1) { BKE_mask_calc_handle_adjacent_interp(spline, new_point, u); - -#endif } - BKE_mask_parent_init(&new_point->parent); - /* select new point */ MASKPOINT_SEL_ALL(new_point); ED_mask_select_flush_all(mask); @@ -382,7 +342,7 @@ static int add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2] new_point = &spline->points[point_index + 1]; - setup_vertex_point(mask, spline, new_point, co, tangent, u, NULL, TRUE, 1.0f); + setup_vertex_point(mask, spline, new_point, co, u, NULL, TRUE); /* TODO - we could pass the spline! */ BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index + 1, true, true); @@ -409,7 +369,6 @@ static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay, float tangent_point[2]; float tangent_co[2]; bool do_cyclic_correct = false; - bool do_recalc_src = false; /* when extruding from endpoints only */ bool do_prev; /* use prev point rather then next?? */ if (!masklay) { @@ -440,11 +399,9 @@ static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay, } else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == 0)) { do_prev = TRUE; - do_recalc_src = TRUE; } else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == spline->tot_point - 1)) { do_prev = FALSE; - do_recalc_src = TRUE; } else { do_prev = FALSE; /* quiet warning */ @@ -482,18 +439,13 @@ static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay, masklay->act_point = new_point; - setup_vertex_point(mask, spline, new_point, co, NULL, 0.5f, ref_point, FALSE, 1.0f); + setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, FALSE); if (masklay->splines_shapes.first) { point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point); BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index, true, true); } - if (do_recalc_src) { - /* TODO, update keyframes in time */ - BKE_mask_calc_handle_point_auto(spline, ref_point, FALSE); - } - WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); return TRUE; @@ -504,7 +456,6 @@ static int add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, con MaskSpline *spline; MaskSplinePoint *point; MaskSplinePoint *new_point = NULL, *ref_point = NULL; - float view_zoom; if (!masklay) { /* if there's no masklay currently operationg on, create new one */ @@ -529,22 +480,7 @@ static int add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, con masklay->act_point = new_point; - { - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - - float zoom_x, zoom_y; - /* calc view zoom in a simplistic way */ - ED_mask_zoom(sa, ar, &zoom_x, &zoom_y); - - view_zoom = zoom_x + zoom_y / 2.0f; - view_zoom = 1.0f / view_zoom; - - /* arbitrary but gives good results */ - view_zoom /= 500.0f; - } - - setup_vertex_point(mask, spline, new_point, co, NULL, 0.5f, ref_point, FALSE, view_zoom); + setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, FALSE); { int point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point); diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c index 24fcbd19fc1..12fcd3c1459 100644 --- a/source/blender/editors/mask/mask_draw.c +++ b/source/blender/editors/mask/mask_draw.c @@ -132,29 +132,122 @@ static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float c BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co); } +static void draw_circle(const float x, const float y, + const float size, const float xscale, const float yscale) +{ + static GLuint displist = 0; + + /* Initialize round circle shape. */ + if (displist == 0) { + GLUquadricObj *qobj; + + displist = glGenLists(1); + glNewList(displist, GL_COMPILE); + + qobj = gluNewQuadric(); + gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); + gluDisk(qobj, 0, 0.7, 8, 1); + gluDeleteQuadric(qobj); + + glEndList(); + } + + glPushMatrix(); + glTranslatef(x, y, 0.0f); + glScalef(1.0f / xscale * size, 1.0f / yscale * size, 1.0f); + glCallList(displist); + glPopMatrix(); +} + +static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoint *point, + const eMaskWhichHandle which_handle, const int draw_type, + const float handle_size, const float xscale, const float yscale, + const float point_pos[2], const float handle_pos[2]) +{ + const BezTriple *bezt = &point->bezt; + char handle_type; + + if (which_handle == MASK_WHICH_HANDLE_STICK || which_handle == MASK_WHICH_HANDLE_LEFT) { + handle_type = bezt->h1; + } + else { + handle_type = bezt->h2; + } + + if (handle_type == HD_VECT) { + return; + } + + /* this could be split into its own loop */ + if (draw_type == MASK_DT_OUTLINE) { + const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff}; + glLineWidth(3); + glColor4ubv(rgb_gray); + glBegin(GL_LINES); + glVertex2fv(point_pos); + glVertex2fv(handle_pos); + glEnd(); + glLineWidth(1); + } + + switch (handle_type) { + case HD_FREE: + UI_ThemeColor(TH_HANDLE_FREE); + break; + case HD_AUTO: + UI_ThemeColor(TH_HANDLE_AUTO); + break; + case HD_ALIGN: + case HD_ALIGN_DOUBLESIDE: + UI_ThemeColor(TH_HANDLE_ALIGN); + break; + } + + glBegin(GL_LINES); + glVertex2fv(point_pos); + glVertex2fv(handle_pos); + glEnd(); + + /* draw handle points */ + if (MASKPOINT_ISSEL_HANDLE(point, which_handle)) { + if (point == mask_layer->act_point) + glColor3f(1.0f, 1.0f, 1.0f); + else + glColor3f(1.0f, 1.0f, 0.0f); + } + else { + glColor3f(0.5f, 0.5f, 0.0f); + } + + draw_circle(handle_pos[0], handle_pos[1], handle_size, xscale, yscale); +} + /* return non-zero if spline is selected */ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline *spline, - const char UNUSED(draw_flag), const char draw_type) + const char draw_flag, const char draw_type, + const float xscale, const float yscale) { const bool is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0; + const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0; + unsigned char rgb_spline[4]; MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline); SpaceClip *sc = CTX_wm_space_clip(C); - int undistort = FALSE; + bool undistort = false; - int i, hsize, tot_feather_point; + int i, handle_size, tot_feather_point; float (*feather_points)[2], (*fp)[2]; if (!spline->tot_point) return; if (sc) - undistort = sc->clip && sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT; + undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0; /* TODO, add this to sequence editor */ - hsize = 4; /* UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE); */ + handle_size = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize; - glPointSize(hsize); + glPointSize(handle_size); mask_spline_color_get(masklay, spline, is_spline_sel, rgb_spline); @@ -202,6 +295,12 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline } MEM_freeN(feather_points); + if (is_smooth) { + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + /* control points */ for (i = 0; i < spline->tot_point; i++) { @@ -210,38 +309,36 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline MaskSplinePoint *point_deform = &points_array[i]; BezTriple *bezt = &point_deform->bezt; - float handle[2]; float vert[2]; - const bool has_handle = BKE_mask_point_has_handle(point); copy_v2_v2(vert, bezt->vec[1]); - BKE_mask_point_handle(point_deform, handle); if (undistort) { mask_point_undistort_pos(sc, vert, vert); - mask_point_undistort_pos(sc, handle, handle); } /* draw handle segment */ - if (has_handle) { - - /* this could be split into its own loop */ - if (draw_type == MASK_DT_OUTLINE) { - const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff}; - glLineWidth(3); - glColor4ubv(rgb_gray); - glBegin(GL_LINES); - glVertex2fv(vert); - glVertex2fv(handle); - glEnd(); - glLineWidth(1); + if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) { + float handle[2]; + BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_STICK, handle); + if (undistort) { + mask_point_undistort_pos(sc, handle, handle); } - - glColor3ubv(rgb_spline); - glBegin(GL_LINES); - glVertex2fv(vert); - glVertex2fv(handle); - glEnd(); + draw_single_handle(masklay, point, MASK_WHICH_HANDLE_STICK, + draw_type, handle_size, xscale, yscale, vert, handle); + } + else { + float handle_left[2], handle_right[2]; + BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_LEFT, handle_left); + BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_RIGHT, handle_right); + if (undistort) { + mask_point_undistort_pos(sc, handle_left, handle_left); + mask_point_undistort_pos(sc, handle_left, handle_left); + } + draw_single_handle(masklay, point, MASK_WHICH_HANDLE_LEFT, + draw_type, handle_size, xscale, yscale, vert, handle_left); + draw_single_handle(masklay, point, MASK_WHICH_HANDLE_RIGHT, + draw_type, handle_size, xscale, yscale, vert, handle_right); } /* draw CV point */ @@ -257,26 +354,14 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline glBegin(GL_POINTS); glVertex2fv(vert); glEnd(); - - /* draw handle points */ - if (has_handle) { - if (MASKPOINT_ISSEL_HANDLE(point)) { - if (point == masklay->act_point) - glColor3f(1.0f, 1.0f, 1.0f); - else - glColor3f(1.0f, 1.0f, 0.0f); - } - else { - glColor3f(0.5f, 0.5f, 0.0f); - } - - glBegin(GL_POINTS); - glVertex2fv(handle); - glEnd(); - } } glPointSize(1.0f); + + if (is_smooth) { + glDisable(GL_LINE_SMOOTH); + glDisable(GL_BLEND); + } } /* #define USE_XOR */ @@ -408,7 +493,7 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (* static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline *spline, const char draw_flag, const char draw_type, const bool is_active, - int width, int height) + const int width, const int height) { const unsigned int resol = max_ii(BKE_mask_spline_feather_resolution(spline, width, height), BKE_mask_spline_resolution(spline, width, height)); @@ -482,7 +567,7 @@ static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline } static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, const char draw_type, - int width, int height) + const int width, const int height, const float xscale, const float yscale) { MaskLayer *masklay; int i; @@ -504,7 +589,7 @@ static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, c if (!(masklay->restrictflag & MASK_RESTRICT_SELECT)) { /* ...and then handles over the curve so they're nicely visible */ - draw_spline_points(C, masklay, spline, draw_flag, draw_type); + draw_spline_points(C, masklay, spline, draw_flag, draw_type, xscale, yscale); } /* show undeform for testing */ @@ -514,7 +599,7 @@ static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, c spline->points_deform = NULL; draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height); // draw_spline_parents(masklay, spline); - draw_spline_points(C, masklay, spline, draw_flag, draw_type); + draw_spline_points(C, masklay, spline, draw_flag, draw_type, xscale, yscale); spline->points_deform = back; } } @@ -525,16 +610,21 @@ void ED_mask_draw(const bContext *C, const char draw_flag, const char draw_type) { ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); Mask *mask = CTX_data_edit_mask(C); int width, height; + float aspx, aspy; + float xscale, yscale; if (!mask) return; ED_mask_get_size(sa, &width, &height); + ED_mask_get_aspect(sa, ar, &aspx, &aspy); + UI_view2d_getscale(&ar->v2d, &xscale, &yscale); - draw_masklays(C, mask, draw_flag, draw_type, width, height); + draw_masklays(C, mask, draw_flag, draw_type, width, height, xscale * aspx, yscale * aspy); } typedef struct ThreadedMaskRasterizeState { @@ -719,7 +809,7 @@ void ED_mask_draw_region(Mask *mask, ARegion *ar, } /* draw! */ - draw_masklays(C, mask, draw_flag, draw_type, width, height); + draw_masklays(C, mask, draw_flag, draw_type, width, height, maxdim * zoomx, maxdim * zoomy); if (do_draw_cb) { ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c index ad287a3af9f..af4645e31ec 100644 --- a/source/blender/editors/mask/mask_edit.c +++ b/source/blender/editors/mask/mask_edit.c @@ -570,8 +570,8 @@ void ED_operatormacros_mask(void) "Add new vertex and slide it", OPTYPE_UNDO | OPTYPE_REGISTER); ot->description = "Add new vertex and slide it"; WM_operatortype_macro_define(ot, "MASK_OT_add_vertex"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); - RNA_boolean_set(otmacro->ptr, "release_confirm", TRUE); + otmacro = WM_operatortype_macro_define(ot, "MASK_OT_slide_point"); + RNA_boolean_set(otmacro->ptr, "is_new_point", TRUE); ot = WM_operatortype_append_macro("MASK_OT_add_feather_vertex_slide", "Add Feather Vertex and Slide", "Add new vertex to feather and slide it", OPTYPE_UNDO | OPTYPE_REGISTER); diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h index 62872e72cb4..d95e07f043a 100644 --- a/source/blender/editors/mask/mask_intern.h +++ b/source/blender/editors/mask/mask_intern.h @@ -73,7 +73,7 @@ bool ED_mask_feather_find_nearest( struct MaskSplinePoint *ED_mask_point_find_nearest( const struct bContext *C, struct Mask *mask, const float normal_co[2], const float threshold, - struct MaskLayer **masklay_r, struct MaskSpline **spline_r, bool *is_handle_r, + struct MaskLayer **masklay_r, struct MaskSpline **spline_r, eMaskWhichHandle *which_handle_r, float *score); void MASK_OT_layer_move(struct wmOperatorType *ot); diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index b9b456177ea..da91c59a094 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -59,9 +59,17 @@ /******************** utility functions *********************/ +static void mask_point_scaled_handle(/*const*/ MaskSplinePoint *point, /*const*/ eMaskWhichHandle which_handle, + const float scalex, const float scaley, float handle[2]) +{ + BKE_mask_point_handle(point, which_handle, handle); + handle[0] *= scalex; + handle[1] *= scaley; +} + MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const float normal_co[2], const float threshold, - MaskLayer **masklay_r, MaskSpline **spline_r, bool *is_handle_r, - float *score) + MaskLayer **masklay_r, MaskSpline **spline_r, + eMaskWhichHandle *which_handle_r, float *score) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); @@ -72,8 +80,9 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const MaskSplinePoint *point = NULL; float co[2]; const float threshold_sq = threshold * threshold; - float len_sq = FLT_MAX, scalex, scaley; - int is_handle = FALSE, width, height; + float len_sq= FLT_MAX, scalex, scaley; + eMaskWhichHandle which_handle = MASK_WHICH_HANDLE_NONE; + int width, height; ED_mask_get_size(sa, &width, &height); ED_mask_pixelspace_factor(sa, ar, &scalex, &scaley); @@ -96,35 +105,64 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const for (i = 0; i < spline->tot_point; i++) { MaskSplinePoint *cur_point = &spline->points[i]; MaskSplinePoint *cur_point_deform = &points_array[i]; - float cur_len_sq, vec[2], handle[2]; + eMaskWhichHandle cur_which_handle; + float cur_len_sq, vec[2]; vec[0] = cur_point_deform->bezt.vec[1][0] * scalex; vec[1] = cur_point_deform->bezt.vec[1][1] * scaley; - if (BKE_mask_point_has_handle(cur_point)) { - BKE_mask_point_handle(cur_point_deform, handle); - handle[0] *= scalex; - handle[1] *= scaley; + cur_len_sq = len_squared_v2v2(co, vec); - cur_len_sq = len_squared_v2v2(co, handle); + if (cur_len_sq < len_sq) { + point_spline = spline; + point_masklay = masklay; + point = cur_point; + len_sq = cur_len_sq; + which_handle = MASK_WHICH_HANDLE_NONE; + } - if (cur_len_sq < len_sq) { - point_masklay = masklay; - point_spline = spline; - point = cur_point; - len_sq = cur_len_sq; - is_handle = TRUE; + if (BKE_mask_point_handles_mode_get(cur_point_deform) == MASK_HANDLE_MODE_STICK) { + float handle[2]; + mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_STICK, scalex, scaley, handle); + cur_len_sq = len_squared_v2v2(co, handle); + cur_which_handle = MASK_WHICH_HANDLE_STICK; + } + else { + float handle_left[2], handle_right[2]; + float len_left_sq, len_right_sq; + mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_LEFT, scalex, scaley, handle_left); + mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_RIGHT, scalex, scaley, handle_right); + + len_left_sq = len_squared_v2v2(co, handle_left); + len_right_sq = len_squared_v2v2(co, handle_right); + if (i == 0) { + if (len_left_sq <= len_right_sq) { + cur_which_handle = MASK_WHICH_HANDLE_LEFT; + cur_len_sq = len_left_sq; + } + else { + cur_which_handle = MASK_WHICH_HANDLE_RIGHT; + cur_len_sq = len_right_sq; + } + } + else { + if (len_right_sq <= len_left_sq) { + cur_which_handle = MASK_WHICH_HANDLE_RIGHT; + cur_len_sq = len_right_sq; + } + else { + cur_which_handle = MASK_WHICH_HANDLE_LEFT; + cur_len_sq = len_left_sq; + } } } - cur_len_sq = len_squared_v2v2(co, vec); - - if (cur_len_sq < len_sq) { - point_spline = spline; + if (cur_len_sq <= len_sq) { point_masklay = masklay; + point_spline = spline; point = cur_point; len_sq = cur_len_sq; - is_handle = FALSE; + which_handle = cur_which_handle; } } } @@ -137,8 +175,8 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const if (spline_r) *spline_r = point_spline; - if (is_handle_r) - *is_handle_r = is_handle; + if (which_handle_r) + *which_handle_r = which_handle; if (score) *score = sqrtf(len_sq); @@ -152,8 +190,8 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const if (spline_r) *spline_r = NULL; - if (is_handle_r) - *is_handle_r = FALSE; + if (which_handle_r) + *which_handle_r = MASK_WHICH_HANDLE_NONE; return NULL; } @@ -423,18 +461,22 @@ typedef struct SlidePointData { float co[2]; float vec[3][3]; + char old_h1, old_h2; Mask *mask; MaskLayer *masklay; MaskSpline *spline, *orig_spline; MaskSplinePoint *point; MaskSplinePointUW *uw; + eMaskWhichHandle which_handle; float handle[2], no[2], feather[2]; int width, height; float weight, weight_scalar; short curvature_only, accurate; short initial_feather, overall_feather; + + bool is_sliding_new_point; } SlidePointData; static bool slide_point_check_initial_feather(MaskSpline *spline) @@ -460,6 +502,41 @@ static bool slide_point_check_initial_feather(MaskSpline *spline) return TRUE; } +static void select_sliding_point(Mask *mask, MaskLayer *mask_layer, MaskSpline *spline, + MaskSplinePoint *point) +{ + ED_mask_select_toggle_all(mask, SEL_DESELECT); + BKE_mask_point_select_set(point, TRUE); + + mask_layer->act_spline = spline; + mask_layer->act_point = point; + ED_mask_select_flush_all(mask); +} + +static void check_sliding_handle_type(MaskSplinePoint *point, eMaskWhichHandle which_handle) +{ + BezTriple *bezt = &point->bezt; + + if (which_handle == MASK_WHICH_HANDLE_LEFT) { + if (bezt->h1 == HD_VECT) { + bezt->h1 = HD_FREE; + } + else if (bezt->h1 == HD_AUTO) { + bezt->h1 = HD_ALIGN_DOUBLESIDE; + bezt->h2 = HD_ALIGN_DOUBLESIDE; + } + } + else if (which_handle == MASK_WHICH_HANDLE_RIGHT) { + if (bezt->h2 == HD_VECT) { + bezt->h2 = HD_FREE; + } + else if (bezt->h2 == HD_AUTO) { + bezt->h1 = HD_ALIGN_DOUBLESIDE; + bezt->h2 = HD_ALIGN_DOUBLESIDE; + } + } +} + static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *event) { ScrArea *sa = CTX_wm_area(C); @@ -472,15 +549,15 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * MaskSplinePoint *point, *cv_point, *feather_point; MaskSplinePointUW *uw = NULL; int width, height, action = SLIDE_ACTION_NONE; - bool is_handle = false; const bool slide_feather = RNA_boolean_get(op->ptr, "slide_feather"); float co[2], cv_score, feather_score; const float threshold = 19; + eMaskWhichHandle which_handle; ED_mask_mouse_pos(sa, ar, event->mval, co); ED_mask_get_size(sa, &width, &height); - cv_point = ED_mask_point_find_nearest(C, mask, co, threshold, &cv_masklay, &cv_spline, &is_handle, &cv_score); + cv_point = ED_mask_point_find_nearest(C, mask, co, threshold, &cv_masklay, &cv_spline, &which_handle, &cv_score); if (ED_mask_feather_find_nearest(C, mask, co, threshold, &feather_masklay, &feather_spline, &feather_point, &uw, &feather_score)) { if (slide_feather || !cv_point || feather_score < cv_score) { @@ -493,7 +570,7 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * } if (cv_point && action == SLIDE_ACTION_NONE) { - if (is_handle) + if (which_handle != MASK_WHICH_HANDLE_NONE) action = SLIDE_ACTION_HANDLE; else action = SLIDE_ACTION_POINT; @@ -504,6 +581,8 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * } if (action != SLIDE_ACTION_NONE) { + select_sliding_point(mask, masklay, spline, point); + customdata = MEM_callocN(sizeof(SlidePointData), "mask slide point data"); customdata->mask = mask; @@ -515,6 +594,13 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * customdata->action = action; customdata->uw = uw; + customdata->old_h1 = point->bezt.h1; + customdata->old_h2 = point->bezt.h2; + + customdata->is_sliding_new_point = RNA_boolean_get(op->ptr, "is_new_point"); + + check_sliding_handle_type(point, which_handle); + if (uw) { float co_uw[2]; float weight_scalar = BKE_mask_point_weight_scalar(spline, point, uw->u); @@ -540,8 +626,10 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * customdata->initial_feather = slide_point_check_initial_feather(spline); copy_m3_m3(customdata->vec, point->bezt.vec); - if (BKE_mask_point_has_handle(point)) - BKE_mask_point_handle(point, customdata->handle); + if (which_handle != MASK_WHICH_HANDLE_NONE) { + BKE_mask_point_handle(point, which_handle, customdata->handle); + } + customdata->which_handle = which_handle; ED_mask_mouse_pos(sa, ar, event->mval, customdata->co); } @@ -550,11 +638,16 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * static int slide_point_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - SlidePointData *slidedata = slide_point_customdata(C, op, event); + Mask *mask = CTX_data_edit_mask(C); + SlidePointData *slidedata; - if (slidedata) { - Mask *mask = CTX_data_edit_mask(C); + if (mask == NULL) { + return OPERATOR_CANCELLED; + } + slidedata = slide_point_customdata(C, op, event); + + if (slidedata) { op->customdata = slidedata; WM_event_add_modal_handler(C, op); @@ -645,6 +738,8 @@ static void cancel_slide_point(SlidePointData *data) } else { copy_m3_m3(data->point->bezt.vec, data->vec); + data->point->bezt.h1 = data->old_h1; + data->point->bezt.h2 = data->old_h2; } } } @@ -695,10 +790,34 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event) sub_v2_v2v2(offco, co, data->co); if (data->accurate) mul_v2_fl(offco, 0.2f); + + if (data->is_sliding_new_point && data->which_handle == MASK_WHICH_HANDLE_STICK) { + if (ELEM(data->point, &data->spline->points[0], + &data->spline->points[data->spline->tot_point - 1])) + { + SWAP(float, offco[0], offco[1]); + offco[1] *= -1; + } + } + add_v2_v2(offco, data->co); add_v2_v2(offco, delta); - BKE_mask_point_set_handle(data->point, offco, data->curvature_only, data->handle, data->vec); + BKE_mask_point_set_handle(data->point, data->which_handle, + offco, data->curvature_only, + data->handle, data->vec); + + if (data->is_sliding_new_point) { + if (ELEM(data->which_handle, MASK_WHICH_HANDLE_LEFT, MASK_WHICH_HANDLE_RIGHT)) { + BezTriple *bezt = &data->point->bezt; + float vec[2]; + short self_handle = (data->which_handle == MASK_WHICH_HANDLE_LEFT) ? 0 : 2; + short other_handle = (data->which_handle == MASK_WHICH_HANDLE_LEFT) ? 2 : 0; + + sub_v2_v2v2(vec, bezt->vec[1], bezt->vec[self_handle]); + add_v2_v2v2(bezt->vec[other_handle], bezt->vec[1], vec); + } + } } else if (data->action == SLIDE_ACTION_POINT) { float delta[2]; @@ -826,6 +945,16 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event) } } + if (data->is_sliding_new_point) { + BezTriple *bezt = &data->point->bezt; + if (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) < FLT_EPSILON) { + bezt->h1 = HD_VECT; + } + if (len_squared_v2v2(bezt->vec[2], bezt->vec[1]) < FLT_EPSILON) { + bezt->h2 = HD_VECT; + } + } + WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask); DAG_id_tag_update(&data->mask->id, 0); @@ -850,6 +979,8 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event) void MASK_OT_slide_point(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Slide Point"; ot->description = "Slide control points"; @@ -858,12 +989,15 @@ void MASK_OT_slide_point(wmOperatorType *ot) /* api callbacks */ ot->invoke = slide_point_invoke; ot->modal = slide_point_modal; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_operator_mask; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_boolean(ot->srna, "slide_feather", 0, "Slide Feather", "First try to slide feather instead of vertex"); + + prop = RNA_def_boolean(ot->srna, "is_new_point", 0, "Slide New Point", "Newly created vertex is being slided"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /******************** toggle cyclic *********************/ @@ -887,6 +1021,7 @@ static int cyclic_toggle_exec(bContext *C, wmOperator *UNUSED(op)) } } + DAG_id_tag_update(&mask->id, 0); WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); return OPERATOR_FINISHED; @@ -1218,7 +1353,25 @@ static int set_handle_type_exec(bContext *C, wmOperator *op) if (MASKPOINT_ISSEL_ANY(point)) { BezTriple *bezt = &point->bezt; - bezt->h1 = bezt->h2 = handle_type; + if (bezt->f2 & SELECT) { + bezt->h1 = handle_type; + bezt->h2 = handle_type; + } + else { + if (bezt->f1 & SELECT) { + bezt->h1 = handle_type; + } + if (bezt->f3 & SELECT) { + bezt->h2 = handle_type; + } + } + + if (handle_type == HD_ALIGN) { + float vec[3]; + sub_v3_v3v3(vec, bezt->vec[0], bezt->vec[1]); + add_v3_v3v3(bezt->vec[2], bezt->vec[1], vec); + } + changed = true; } } @@ -1239,7 +1392,9 @@ void MASK_OT_handle_type_set(wmOperatorType *ot) static EnumPropertyItem editcurve_handle_type_items[] = { {HD_AUTO, "AUTO", 0, "Auto", ""}, {HD_VECT, "VECTOR", 0, "Vector", ""}, - {HD_ALIGN, "ALIGNED", 0, "Aligned", ""}, + {HD_ALIGN, "ALIGNED", 0, "Aligned Single", ""}, + {HD_ALIGN_DOUBLESIDE, "ALIGNED_DOUBLESIDE", 0, "Aligned", ""}, + {HD_FREE, "FREE", 0, "Free", ""}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c index 16fd8414f22..29b5714be59 100644 --- a/source/blender/editors/mask/mask_select.c +++ b/source/blender/editors/mask/mask_select.c @@ -255,38 +255,36 @@ static int select_exec(bContext *C, wmOperator *op) bool extend = RNA_boolean_get(op->ptr, "extend"); bool deselect = RNA_boolean_get(op->ptr, "deselect"); bool toggle = RNA_boolean_get(op->ptr, "toggle"); - - bool is_handle = 0; + eMaskWhichHandle which_handle; const float threshold = 19; RNA_float_get_array(op->ptr, "location", co); - point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, &is_handle, NULL); + point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, &which_handle, NULL); if (extend == false && deselect == false && toggle == false) ED_mask_select_toggle_all(mask, SEL_DESELECT); if (point) { - - if (is_handle) { + if (which_handle != MASK_WHICH_HANDLE_NONE) { if (extend) { masklay->act_spline = spline; masklay->act_point = point; - BKE_mask_point_select_set_handle(point, TRUE); + BKE_mask_point_select_set_handle(point, which_handle, TRUE); } else if (deselect) { - BKE_mask_point_select_set_handle(point, FALSE); + BKE_mask_point_select_set_handle(point, which_handle, FALSE); } else { masklay->act_spline = spline; masklay->act_point = point; - if (!MASKPOINT_ISSEL_HANDLE(point)) { - BKE_mask_point_select_set_handle(point, TRUE); + if (!MASKPOINT_ISSEL_HANDLE(point, which_handle)) { + BKE_mask_point_select_set_handle(point, which_handle, TRUE); } else if (toggle) { - BKE_mask_point_select_set_handle(point, FALSE); + BKE_mask_point_select_set_handle(point, which_handle, FALSE); } } } @@ -444,11 +442,11 @@ static int border_select_exec(bContext *C, wmOperator *op) if (BLI_rctf_isect_pt_v(&rectf, point_deform->bezt.vec[1])) { BKE_mask_point_select_set(point, mode == GESTURE_MODAL_SELECT); - BKE_mask_point_select_set_handle(point, mode == GESTURE_MODAL_SELECT); + BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, mode == GESTURE_MODAL_SELECT); } else if (!extend) { BKE_mask_point_select_set(point, FALSE); - BKE_mask_point_select_set_handle(point, FALSE); + BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, FALSE); } changed = true; @@ -531,7 +529,7 @@ static bool do_lasso_select_mask(bContext *C, const int mcords[][2], short moves BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) { BKE_mask_point_select_set(point, select); - BKE_mask_point_select_set_handle(point, select); + BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, select); } changed = true; @@ -649,7 +647,7 @@ static int circle_select_exec(bContext *C, wmOperator *op) if (mask_spline_point_inside_ellipse(&point_deform->bezt, offset, ellipse)) { BKE_mask_point_select_set(point, mode == GESTURE_MODAL_SELECT); - BKE_mask_point_select_set_handle(point, mode == GESTURE_MODAL_SELECT); + BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, mode == GESTURE_MODAL_SELECT); changed = true; } @@ -702,14 +700,12 @@ static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE MaskSplinePoint *point = NULL; float co[2]; int do_select = !RNA_boolean_get(op->ptr, "deselect"); - - bool is_handle = false; const float threshold = 19; bool changed = false; ED_mask_mouse_pos(sa, ar, event->mval, co); - point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, &is_handle, NULL); + point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, NULL, NULL); if (point) { ED_mask_spline_select_set(spline, do_select); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 886dea2e34b..0b3238c7d1e 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -6584,8 +6584,67 @@ typedef struct TransDataMasking { MaskSplinePoint *point; float parent_matrix[3][3]; float parent_inverse_matrix[3][3]; + char orig_handle_type; + + eMaskWhichHandle which_handle; } TransDataMasking; +static void MaskHandleToTransData(MaskSplinePoint *point, eMaskWhichHandle which_handle, + TransData *td, TransData2D *td2d, TransDataMasking *tdm, + const float asp[2], + /*const*/ float parent_matrix[3][3], + /*const*/ float parent_inverse_matrix[3][3]) +{ + BezTriple *bezt = &point->bezt; + short is_sel_any = MASKPOINT_ISSEL_ANY(point); + + tdm->point = point; + copy_m3_m3(tdm->vec, bezt->vec); + + tdm->is_handle = TRUE; + copy_m3_m3(tdm->parent_matrix, parent_matrix); + copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix); + + BKE_mask_point_handle(point, which_handle, tdm->handle); + tdm->which_handle = which_handle; + + copy_v2_v2(tdm->orig_handle, tdm->handle); + + mul_v2_m3v2(td2d->loc, parent_matrix, tdm->handle); + td2d->loc[0] *= asp[0]; + td2d->loc[1] *= asp[1]; + td2d->loc[2] = 0.0f; + + td2d->loc2d = tdm->handle; + + td->flag = 0; + td->loc = td2d->loc; + mul_v2_m3v2(td->center, parent_matrix, bezt->vec[1]); + copy_v3_v3(td->iloc, td->loc); + + memset(td->axismtx, 0, sizeof(td->axismtx)); + td->axismtx[2][2] = 1.0f; + + td->ext = NULL; + td->val = NULL; + + if (is_sel_any) { + td->flag |= TD_SELECTED; + } + + td->dist = 0.0; + + unit_m3(td->mtx); + unit_m3(td->smtx); + + if (which_handle == MASK_WHICH_HANDLE_LEFT) { + tdm->orig_handle_type = bezt->h1; + } + else if (which_handle == MASK_WHICH_HANDLE_RIGHT) { + tdm->orig_handle_type = bezt->h2; + } +} + static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point, TransData *td, TransData2D *td2d, TransDataMasking *tdm, const int propmode, const float asp[2]) @@ -6595,14 +6654,15 @@ static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point, const bool is_sel_any = MASKPOINT_ISSEL_ANY(point); float parent_matrix[3][3], parent_inverse_matrix[3][3]; - tdm->point = point; - copy_m3_m3(tdm->vec, bezt->vec); - BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix); invert_m3_m3(parent_inverse_matrix, parent_matrix); if (propmode || is_sel_point) { int i; + + tdm->point = point; + copy_m3_m3(tdm->vec, bezt->vec); + for (i = 0; i < 3; i++) { copy_m3_m3(tdm->parent_matrix, parent_matrix); copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix); @@ -6645,49 +6705,64 @@ static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point, unit_m3(td->mtx); unit_m3(td->smtx); + if (i == 0) { + tdm->orig_handle_type = bezt->h1; + } + else if (i == 3) { + tdm->orig_handle_type = bezt->h2; + } + td++; td2d++; tdm++; } } else { - tdm->is_handle = TRUE; - copy_m3_m3(tdm->parent_matrix, parent_matrix); - copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix); - - BKE_mask_point_handle(point, tdm->handle); - - copy_v2_v2(tdm->orig_handle, tdm->handle); - - mul_v2_m3v2(td2d->loc, parent_matrix, tdm->handle); - td2d->loc[0] *= asp[0]; - td2d->loc[1] *= asp[1]; - td2d->loc[2] = 0.0f; + if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) { + MaskHandleToTransData(point, MASK_WHICH_HANDLE_STICK, + td, td2d, tdm, asp, parent_matrix, + parent_inverse_matrix); - td2d->loc2d = tdm->handle; + td++; + td2d++; + tdm++; + } + else { + if (bezt->f1 & SELECT) { + MaskHandleToTransData(point, MASK_WHICH_HANDLE_LEFT, + td, td2d, tdm, asp, parent_matrix, + parent_inverse_matrix); - td->flag = 0; - td->loc = td2d->loc; - mul_v2_m3v2(td->center, parent_matrix, bezt->vec[1]); - copy_v3_v3(td->iloc, td->loc); + if (bezt->h1 == HD_VECT) { + bezt->h1 = HD_FREE; + } + else if (bezt->h1 == HD_AUTO) { + bezt->h1 = HD_ALIGN_DOUBLESIDE; + bezt->h2 = HD_ALIGN_DOUBLESIDE; + } - memset(td->axismtx, 0, sizeof(td->axismtx)); - td->axismtx[2][2] = 1.0f; + td++; + td2d++; + tdm++; + } + if (bezt->f3 & SELECT) { + MaskHandleToTransData(point, MASK_WHICH_HANDLE_RIGHT, + td, td2d, tdm, asp, parent_matrix, + parent_inverse_matrix); - td->ext = NULL; - td->val = NULL; + if (bezt->h2 == HD_VECT) { + bezt->h2 = HD_FREE; + } + else if (bezt->h2 == HD_AUTO) { + bezt->h1 = HD_ALIGN_DOUBLESIDE; + bezt->h2 = HD_ALIGN_DOUBLESIDE; + } - if (is_sel_any) { - td->flag |= TD_SELECTED; + td++; + td2d++; + tdm++; + } } - - td->dist = 0.0; - - unit_m3(td->mtx); - unit_m3(td->smtx); - - td++; - td2d++; } } @@ -6731,10 +6806,23 @@ static void createTransMaskingData(bContext *C, TransInfo *t) MaskSplinePoint *point = &spline->points[i]; if (MASKPOINT_ISSEL_ANY(point)) { - if (MASKPOINT_ISSEL_KNOT(point)) + if (MASKPOINT_ISSEL_KNOT(point)) { countsel += 3; - else - countsel += 1; + } + else { + if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) { + countsel += 1; + } + else { + BezTriple *bezt = &point->bezt; + if (bezt->f1 & SELECT) { + countsel++; + } + if (bezt->f3 & SELECT) { + countsel++; + } + } + } } if (propmode) @@ -6782,9 +6870,24 @@ static void createTransMaskingData(bContext *C, TransInfo *t) tdm += 3; } else { - td++; - td2d++; - tdm++; + if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) { + td++; + td2d++; + tdm++; + } + else { + BezTriple *bezt = &point->bezt; + if (bezt->f1 & SELECT) { + td++; + td2d++; + tdm++; + } + if (bezt->f3 & SELECT) { + td++; + td2d++; + tdm++; + } + } } } } @@ -6810,10 +6913,20 @@ void flushTransMasking(TransInfo *t) mul_m3_v2(tdm->parent_inverse_matrix, td->loc2d); if (tdm->is_handle) { - BKE_mask_point_set_handle(tdm->point, td->loc2d, + BKE_mask_point_set_handle(tdm->point, tdm->which_handle, + td->loc2d, (t->flag & T_ALT_TRANSFORM) != 0, tdm->orig_handle, tdm->vec); } + + if (t->state == TRANS_CANCEL) { + if (tdm->which_handle == MASK_WHICH_HANDLE_LEFT) { + tdm->point->bezt.h1 = tdm->orig_handle_type; + } + else if (tdm->which_handle == MASK_WHICH_HANDLE_RIGHT) { + tdm->point->bezt.h2 = tdm->orig_handle_type; + } + } } } diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 0c9e9b01a76..2d3a28fbd41 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -354,7 +354,8 @@ typedef enum eBezTriple_Handle { HD_AUTO = 1, HD_VECT = 2, HD_ALIGN = 3, - HD_AUTO_ANIM = 4 /* auto-clamped handles for animation */ + HD_AUTO_ANIM = 4, /* auto-clamped handles for animation */ + HD_ALIGN_DOUBLESIDE = 5, /* align handles, displayed both of them. used for masks */ } eBezTriple_Handle; /* interpolation modes (used only for BezTriple->ipo) */ diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c index 31e6b0e48e2..29bc15f1dbe 100644 --- a/source/blender/makesrna/intern/rna_mask.c +++ b/source/blender/makesrna/intern/rna_mask.c @@ -312,12 +312,83 @@ static int rna_MaskSplinePoint_handle_type_get(PointerRNA *ptr) return bezt->h1; } +static MaskSpline *mask_spline_from_point(Mask *mask, MaskSplinePoint *point) +{ + MaskLayer *mask_layer; + for (mask_layer = mask->masklayers.first; + mask_layer; + mask_layer = mask_layer->next) + { + MaskSpline *spline; + for (spline = mask_layer->splines.first; + spline; + spline = spline->next) + { + if (point >= spline->points && point < spline->points + spline->tot_point) { + return spline; + } + } + } + return NULL; +} + +static void mask_point_check_stick(MaskSplinePoint *point) +{ + BezTriple *bezt = &point->bezt; + if (bezt->h1 == HD_ALIGN && bezt->h2 == HD_ALIGN) { + float vec[3]; + sub_v3_v3v3(vec, bezt->vec[0], bezt->vec[1]); + add_v3_v3v3(bezt->vec[2], bezt->vec[1], vec); + } +} + static void rna_MaskSplinePoint_handle_type_set(PointerRNA *ptr, int value) { MaskSplinePoint *point = (MaskSplinePoint *) ptr->data; BezTriple *bezt = &point->bezt; + MaskSpline *spline = mask_spline_from_point((Mask *) ptr->id.data, point); bezt->h1 = bezt->h2 = value; + mask_point_check_stick(point); + BKE_mask_calc_handle_point(spline, point); +} + +static int rna_MaskSplinePoint_handle_left_type_get(PointerRNA *ptr) +{ + MaskSplinePoint *point = (MaskSplinePoint *) ptr->data; + BezTriple *bezt = &point->bezt; + + return bezt->h1; +} + +static void rna_MaskSplinePoint_handle_left_type_set(PointerRNA *ptr, int value) +{ + MaskSplinePoint *point = (MaskSplinePoint *) ptr->data; + BezTriple *bezt = &point->bezt; + MaskSpline *spline = mask_spline_from_point((Mask *) ptr->id.data, point); + + bezt->h1 = value; + mask_point_check_stick(point); + BKE_mask_calc_handle_point(spline, point); +} + +static int rna_MaskSplinePoint_handle_right_type_get(PointerRNA *ptr) +{ + MaskSplinePoint *point = (MaskSplinePoint *) ptr->data; + BezTriple *bezt = &point->bezt; + + return bezt->h2; +} + +static void rna_MaskSplinePoint_handle_right_type_set(PointerRNA *ptr, int value) +{ + MaskSplinePoint *point = (MaskSplinePoint *) ptr->data; + BezTriple *bezt = &point->bezt; + MaskSpline *spline = mask_spline_from_point((Mask *) ptr->id.data, point); + + bezt->h2 = value; + mask_point_check_stick(point); + BKE_mask_calc_handle_point(spline, point); } /* ** API ** */ @@ -608,7 +679,9 @@ static void rna_def_maskSplinePoint(BlenderRNA *brna) static EnumPropertyItem handle_type_items[] = { {HD_AUTO, "AUTO", 0, "Auto", ""}, {HD_VECT, "VECTOR", 0, "Vector", ""}, - {HD_ALIGN, "ALIGNED", 0, "Aligned", ""}, + {HD_ALIGN, "ALIGNED", 0, "Aligned Single", ""}, + {HD_ALIGN_DOUBLESIDE, "ALIGNED_DOUBLESIDE", 0, "Aligned", ""}, + {HD_FREE, "FREE", 0, "Free", ""}, {0, NULL, 0, NULL, NULL}}; rna_def_maskSplinePointUW(brna); @@ -642,6 +715,27 @@ static void rna_def_maskSplinePoint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Handle Type", "Handle type"); RNA_def_property_update(prop, 0, "rna_Mask_update_data"); + /* handle_type */ + prop = RNA_def_property(srna, "handle_left_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_funcs(prop, "rna_MaskSplinePoint_handle_left_type_get", "rna_MaskSplinePoint_handle_left_type_set", NULL); + RNA_def_property_enum_items(prop, handle_type_items); + RNA_def_property_ui_text(prop, "Handle 1 Type", "Handle type"); + RNA_def_property_update(prop, 0, "rna_Mask_update_data"); + + /* handle_right */ + prop = RNA_def_property(srna, "handle_right_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_funcs(prop, "rna_MaskSplinePoint_handle_right_type_get", "rna_MaskSplinePoint_handle_right_type_set", NULL); + RNA_def_property_enum_items(prop, handle_type_items); + RNA_def_property_ui_text(prop, "Handle 2 Type", "Handle type"); + RNA_def_property_update(prop, 0, "rna_Mask_update_data"); + + /* weight */ + prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "bezt.weight"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_text(prop, "Weight", "Weight of the point"); + RNA_def_property_update(prop, 0, "rna_Mask_update_data"); + /* select */ prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "bezt.f1", SELECT); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 41953fb0239..fd8d8aede87 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -1292,7 +1292,7 @@ static void rna_def_userdef_theme_spaces_face(StructRNA *srna) RNA_def_property_update(prop, 0, "rna_userdef_update"); } -static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, short incl_nurbs) +static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs, bool incl_lastsel, bool incl_vector) { PropertyRNA *prop; @@ -1340,11 +1340,19 @@ static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, short incl_nurb RNA_def_property_ui_text(prop, "Auto handle color", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop = RNA_def_property(srna, "handle_vect", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "handle_vect"); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Vector handle color", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); + if (incl_vector) { + prop = RNA_def_property(srna, "handle_vect", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "handle_vect"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Vector handle color", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "handle_sel_vect", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "handle_sel_vect"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Vector handle selected color", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + } prop = RNA_def_property(srna, "handle_align", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "handle_align"); @@ -1364,19 +1372,13 @@ static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, short incl_nurb RNA_def_property_ui_text(prop, "Auto handle selected color", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop = RNA_def_property(srna, "handle_sel_vect", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "handle_sel_vect"); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Vector handle selected color", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop = RNA_def_property(srna, "handle_sel_align", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "handle_sel_align"); RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Align handle selected color", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - if (incl_nurbs == 0) { + if (incl_nurbs == false) { /* assume that when nurbs are off, this is for 2D (i.e. anim) editors */ prop = RNA_def_property(srna, "handle_auto_clamped", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "handle_auto_clamped"); @@ -1391,11 +1393,13 @@ static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, short incl_nurb RNA_def_property_update(prop, 0, "rna_userdef_update"); } - prop = RNA_def_property(srna, "lastsel_point", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "lastsel_point"); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Last selected point", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); + if (incl_lastsel) { + prop = RNA_def_property(srna, "lastsel_point", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "lastsel_point"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Last selected point", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + } } static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna) @@ -1484,7 +1488,7 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna) rna_def_userdef_theme_spaces_vertex(srna); rna_def_userdef_theme_spaces_edge(srna); rna_def_userdef_theme_spaces_face(srna); - rna_def_userdef_theme_spaces_curves(srna, 1); + rna_def_userdef_theme_spaces_curves(srna, true, true, true); prop = RNA_def_property(srna, "extra_edge_len", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); @@ -1628,7 +1632,7 @@ static void rna_def_userdef_theme_space_graph(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_userdef_update"); rna_def_userdef_theme_spaces_vertex(srna); - rna_def_userdef_theme_spaces_curves(srna, 0); + rna_def_userdef_theme_spaces_curves(srna, false, true, true); prop = RNA_def_property(srna, "handle_vertex", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); @@ -2247,6 +2251,8 @@ static void rna_def_userdef_theme_space_image(BlenderRNA *brna) RNA_def_property_array(prop, 4); RNA_def_property_ui_text(prop, "Other Object UVs", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); + + rna_def_userdef_theme_spaces_curves(srna, false, false, false); } static void rna_def_userdef_theme_space_seq(BlenderRNA *brna) @@ -2759,6 +2765,8 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna) RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Strips Selected", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); + + rna_def_userdef_theme_spaces_curves(srna, false, false, false); } static void rna_def_userdef_themes(BlenderRNA *brna) |