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
This commit is contained in:
Sergey Sharybin 2013-10-30 10:38:45 +01:00
parent 6e5e3b73f3
commit 1af69b6df3
15 changed files with 871 additions and 379 deletions

View File

@ -172,9 +172,6 @@ class MASK_PT_point():
point = mask.layers.active.splines.active_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

View File

@ -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

View File

@ -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]);

View File

@ -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;
sub_v2_v2v2(vec, point->bezt.vec[0], point->bezt.vec[1]);
if (which_handle == MASK_WHICH_HANDLE_STICK) {
float vec[2];
handle[0] = (point->bezt.vec[1][0] + vec[1]);
handle[1] = (point->bezt.vec[1][1] - vec[0]);
sub_v2_v2v2(vec, bezt->vec[0], bezt->vec[1]);
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);
sub_v2_v2v2(vec, r1, r0);
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);
}
n[0] = -vec[1];
n[1] = vec[0];
sub_v2_v2v2(dir1, co, prev_co);
sub_v2_v2v2(dir2, next_co, co);
normalize_v2(n);
normalize_v2(dir1);
normalize_v2(dir2);
add_v2_v2v2(dir, dir1, dir2);
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];

View File

@ -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;

View File

@ -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,82 +251,10 @@ 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_calc_handle_adjacent_interp(spline, new_point, u);
#endif
}
BKE_mask_parent_init(&new_point->parent);
if (spline->tot_point != 1) {
BKE_mask_calc_handle_adjacent_interp(spline, new_point, u);
}
/* select new point */
MASKPOINT_SEL_ALL(new_point);
@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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,27 +105,12 @@ 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, handle);
if (cur_len_sq < len_sq) {
point_masklay = masklay;
point_spline = spline;
point = cur_point;
len_sq = cur_len_sq;
is_handle = TRUE;
}
}
cur_len_sq = len_squared_v2v2(co, vec);
if (cur_len_sq < len_sq) {
@ -124,7 +118,51 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const
point_masklay = masklay;
point = cur_point;
len_sq = cur_len_sq;
is_handle = FALSE;
which_handle = MASK_WHICH_HANDLE_NONE;
}
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;
}
}
}
if (cur_len_sq <= len_sq) {
point_masklay = masklay;
point_spline = spline;
point = cur_point;
len_sq = cur_len_sq;
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 (mask == NULL) {
return OPERATOR_CANCELLED;
}
slidedata = slide_point_customdata(C, op, event);
if (slidedata) {
Mask *mask = CTX_data_edit_mask(C);
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}
};

View File

@ -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);

View File

@ -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);
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);
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;
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++;
td2d++;
tdm++;
}
else {
if (bezt->f1 & SELECT) {
MaskHandleToTransData(point, MASK_WHICH_HANDLE_LEFT,
td, td2d, tdm, asp, parent_matrix,
parent_inverse_matrix);
td->dist = 0.0;
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;
}
unit_m3(td->mtx);
unit_m3(td->smtx);
td++;
td2d++;
tdm++;
}
if (bezt->f3 & SELECT) {
MaskHandleToTransData(point, MASK_WHICH_HANDLE_RIGHT,
td, td2d, tdm, asp, parent_matrix,
parent_inverse_matrix);
td++;
td2d++;
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;
}
td++;
td2d++;
tdm++;
}
}
}
}
@ -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;
}
}
}
}

View File

@ -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) */

View File

@ -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);

View File

@ -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)