diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2013-10-30 13:38:45 +0400 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2014-03-28 15:54:38 +0400 |
commit | 1af69b6df3c538bd329201520abaa5058a1ff0ca (patch) | |
tree | 9e926a25b1175d3ae61db584b2d5dde2dd9131e9 /source/blender/blenkernel/intern/mask.c | |
parent | 6e5e3b73f37f952420d87a3d8acd07a7f68dd5a3 (diff) |
Implement asymmetric and free handles type for masks
Summary:
The title actually says it all, it's just possible to
have independent free handles for mask splines. Also
it's now possible to have aligned handles displayed
as independent handles.
Required changes in quite a few places, but they're
rather straightforward.
From user perspective there's one really visible change
which is removed Handle Type menu from the panel. With
asymmetric handles it's not clear which handle type to
display there. So now the only way to change handle type
is via V-key menu.
Rewrote normal evaluation function to make it deal
with new type of handles we support. Now it works in
the following way:
- Offset the original spline by maximal weight
- Calculate vector between corresponding U positions
on offset and original spline
- Normalize this vector.
Seems to be giving more adequate results and doesn't
tend to self-intersect as much as old behavior used to,
There're still some changes which needed to be done, but
which are planned for further patch:
- Support colors and handle size via themes.
- Make handles color-coded, just the same as done for
regular bezier splines in 3D viewport.
Additional changes to make roto workflow even better:
- Use circles to draw handles
- Support AA for handles
- Change click-create-drag to change curvature of the
spline instead of adjusting point position.
Reviewers: campbellbarton
CC: sebastian_k, hype, cronk
Differential Revision: http://developer.blender.org/D121
Diffstat (limited to 'source/blender/blenkernel/intern/mask.c')
-rw-r--r-- | source/blender/blenkernel/intern/mask.c | 185 |
1 files changed, 135 insertions, 50 deletions
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]; |