diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index e834712ffe9..d09effc8ff3 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -63,9 +63,11 @@ class CLIP_HT_header(Header): toolsettings = context.tool_settings row = layout.row(align=True) - row.prop(toolsettings, "use_proportional_edit_mask", text="", icon_only=True) + row.prop(toolsettings, "use_proportional_edit_mask", + text="", icon_only=True) if toolsettings.use_proportional_edit_objects: - row.prop(toolsettings, "proportional_edit_falloff", text="", icon_only=True) + row.prop(toolsettings, "proportional_edit_falloff", + text="", icon_only=True) elif sc.view == 'GRAPH': row = layout.row(align=True) @@ -289,7 +291,8 @@ class CLIP_PT_tools_solve(CLIP_PT_tracking_panel, Panel): col.prop(settings, "keyframe_b") col = layout.column(align=True) - col.active = tracking_object.is_camera and not settings.use_tripod_solver + col.active = (tracking_object.is_camera and + not settings.use_tripod_solver) col.label(text="Refine:") col.prop(settings, "refine_intrinsics", text="") @@ -723,13 +726,16 @@ class CLIP_PT_active_mask_point(Panel): clip = parent.id tracking = clip.tracking - col.prop_search(parent, "parent", tracking, "objects", icon='OBJECT_DATA', text="Object:") + col.prop_search(parent, "parent", tracking, + "objects", icon='OBJECT_DATA', text="Object:") if parent.parent and parent.parent in tracking.objects: - object = clip.tracking.objects[parent.parent] - col.prop_search(parent, "sub_parent", object, "tracks", icon='ANIM_DATA', text="Track:") + object = tracking.objects[parent.parent] + col.prop_search(parent, "sub_parent", object, + "tracks", icon='ANIM_DATA', text="Track:") else: - col.prop_search(parent, "sub_parent", clip.tracking, "tracks", icon='ANIM_DATA', text="Track:") + col.prop_search(parent, "sub_parent", tracking, + "tracks", icon='ANIM_DATA', text="Track:") class CLIP_PT_display(CLIP_PT_clip_view_panel, Panel): @@ -1210,6 +1216,7 @@ class CLIP_MT_mask(Menu): layout.separator() layout.operator("mask.cyclic_toggle") layout.operator("mask.switch_direction") + layout.operator("mask.feather_weight_clear") # TODO, better place? layout.separator() layout.operator("mask.parent_clear") diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index 3f837f995ce..f426d96cd5e 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -69,7 +69,14 @@ float (*BKE_mask_spline_feather_points(struct MaskSpline *spline, int *tot_feath void BKE_mask_point_direction_switch(struct MaskSplinePoint *point); void BKE_mask_spline_direction_switch(struct MaskLayer *masklay, struct MaskSpline *spline); -float BKE_mask_spline_project_co(struct MaskSpline *spline, struct MaskSplinePoint *point, float start_u, const float co[2]); + +typedef enum { + MASK_PROJ_NEG = -1, + MASK_PROJ_ANY = 0, + MASK_PROJ_POS = 1 +} eMaskSign; +float BKE_mask_spline_project_co(struct MaskSpline *spline, struct MaskSplinePoint *point, + float start_u, const float co[2], const eMaskSign sign); /* point */ int BKE_mask_point_has_handle(struct MaskSplinePoint *point); diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index b904b78ffdd..99333411d8a 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -410,8 +410,6 @@ void BKE_mask_point_direction_switch(MaskSplinePoint *point) } } -//typedef (float)[MASK_OBJECT_SHAPE_ELEM_SIZE] MaskLayerShapeElem; - typedef struct MaskLayerShapeElem { float value[MASK_OBJECT_SHAPE_ELEM_SIZE]; } MaskLayerShapeElem; @@ -467,7 +465,8 @@ void BKE_mask_spline_direction_switch(MaskLayer *masklay, MaskSpline *spline) } -float BKE_mask_spline_project_co(MaskSpline *spline, MaskSplinePoint *point, float start_u, const float co[2]) +float BKE_mask_spline_project_co(MaskSpline *spline, MaskSplinePoint *point, + float start_u, const float co[2], const eMaskSign sign) { const float proj_eps = 1e-3; const float proj_eps_squared = proj_eps * proj_eps; @@ -475,6 +474,8 @@ float BKE_mask_spline_project_co(MaskSpline *spline, MaskSplinePoint *point, flo float u = -1.0f, du = 1.0f / N, u1 = start_u, u2 = start_u; float ang = -1.0f; + BLI_assert(ABS(sign) <= 1); /* (-1, 0, 1) */ + while (u1 > 0.0f || u2 < 1.0f) { float n1[2], n2[2], co1[2], co2[2]; float v1[2], v2[2]; @@ -485,19 +486,25 @@ float BKE_mask_spline_project_co(MaskSpline *spline, MaskSplinePoint *point, flo BKE_mask_point_normal(spline, point, u1, n1); sub_v2_v2v2(v1, co, co1); - if (len_squared_v2(v1) > proj_eps_squared) { - ang1 = angle_v2v2(v1, n1); - if (ang1 > M_PI / 2.0f) - ang1 = M_PI - ang1; + if ((sign == MASK_PROJ_ANY) || + ((sign == MASK_PROJ_NEG) && (dot_v2v2(v1, n1) <= 0.0f)) || + ((sign == MASK_PROJ_POS) && (dot_v2v2(v1, n1) >= 0.0f))) + { - if (ang < 0.0f || ang1 < ang) { - ang = ang1; - u = u1; + if (len_squared_v2(v1) > proj_eps_squared) { + ang1 = angle_v2v2(v1, n1); + if (ang1 > M_PI / 2.0f) + ang1 = M_PI - ang1; + + if (ang < 0.0f || ang1 < ang) { + ang = ang1; + u = u1; + } + } + else { + u = u1; + break; } - } - else { - u = u1; - break; } } @@ -506,19 +513,25 @@ float BKE_mask_spline_project_co(MaskSpline *spline, MaskSplinePoint *point, flo BKE_mask_point_normal(spline, point, u2, n2); sub_v2_v2v2(v2, co, co2); - if (len_squared_v2(v2) > proj_eps_squared) { - ang2 = angle_v2v2(v2, n2); - if (ang2 > M_PI / 2.0f) - ang2 = M_PI - ang2; + if ((sign == MASK_PROJ_ANY) || + ((sign == MASK_PROJ_NEG) && (dot_v2v2(v2, n2) <= 0.0f)) || + ((sign == MASK_PROJ_POS) && (dot_v2v2(v2, n2) >= 0.0f))) + { - if (ang2 < ang) { - ang = ang2; - u = u2; + if (len_squared_v2(v2) > proj_eps_squared) { + ang2 = angle_v2v2(v2, n2); + if (ang2 > M_PI / 2.0f) + ang2 = M_PI - ang2; + + if (ang2 < ang) { + ang = ang2; + u = u2; + } + } + else { + u = u2; + break; } - } - else { - u = u2; - break; } } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index daba096696c..2d9c6ee7657 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2242,7 +2242,7 @@ static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, Pointe } } else if (itemptr->type == &RNA_MaskLayer) { - split = uiLayoutSplit(sub, 0.66f, 0); + split = uiLayoutSplit(sub, 0.5f, 0); uiItemL(split, name, icon); diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index cdfdde4ef31..82f82862577 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -150,7 +150,7 @@ static int find_nearest_diff_point(bContext *C, Mask *mask, const float normal_c *point_r = point; if (u_r) { - u = BKE_mask_spline_project_co(point_spline, point, u, normal_co); + u = BKE_mask_spline_project_co(point_spline, point, u, normal_co, MASK_PROJ_ANY); *u_r = u; } diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c index 9a32cff04c3..34d297155f9 100644 --- a/source/blender/editors/mask/mask_edit.c +++ b/source/blender/editors/mask/mask_edit.c @@ -212,6 +212,9 @@ void ED_operatortypes_mask(void) WM_operatortype_append(MASK_OT_hide_view_clear); WM_operatortype_append(MASK_OT_hide_view_set); + /* feather */ + WM_operatortype_append(MASK_OT_feather_weight_clear); + /* shape */ WM_operatortype_append(MASK_OT_slide_point); WM_operatortype_append(MASK_OT_cyclic_toggle); @@ -293,6 +296,7 @@ void ED_keymap_mask(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MASK_OT_cyclic_toggle", CKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "MASK_OT_slide_point", LEFTMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "MASK_OT_handle_type_set", VKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "MASK_OT_feather_weight_clear", SKEY, KM_PRESS, KM_ALT, 0); /* relationships */ WM_keymap_add_item(keymap, "MASK_OT_parent_set", PKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h index d2efab8613a..9ac55f22fd9 100644 --- a/source/blender/editors/mask/mask_intern.h +++ b/source/blender/editors/mask/mask_intern.h @@ -54,6 +54,7 @@ void MASK_OT_delete(struct wmOperatorType *ot); void MASK_OT_hide_view_clear(struct wmOperatorType *ot); void MASK_OT_hide_view_set(struct wmOperatorType *ot); +void MASK_OT_feather_weight_clear(struct wmOperatorType *ot); void MASK_OT_switch_direction(struct wmOperatorType *ot); void MASK_OT_handle_type_set(struct wmOperatorType *ot); diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index a0c79f4c2c9..dea5345c69f 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -355,10 +355,12 @@ void MASK_OT_layer_remove(wmOperatorType *ot) /******************** slide *********************/ -#define SLIDE_ACTION_NONE 0 -#define SLIDE_ACTION_POINT 1 -#define SLIDE_ACTION_HANDLE 2 -#define SLIDE_ACTION_FEATHER 3 +enum { + SLIDE_ACTION_NONE = 0, + SLIDE_ACTION_POINT = 1, + SLIDE_ACTION_HANDLE = 2, + SLIDE_ACTION_FEATHER = 3 +}; typedef struct SlidePointData { int action; @@ -648,7 +650,29 @@ static int slide_point_modal(bContext *C, wmOperator *op, wmEvent *event) add_v2_v2v2(offco, data->feather, dco); if (data->uw) { - float u = BKE_mask_spline_project_co(data->spline, data->point, data->uw->u, offco); + /* project on both sides and find the closest one, + * prevents flickering when projecting onto both sides can happen */ + const float u_pos = BKE_mask_spline_project_co(data->spline, data->point, + data->uw->u, offco, MASK_PROJ_NEG); + const float u_neg = BKE_mask_spline_project_co(data->spline, data->point, + data->uw->u, offco, MASK_PROJ_POS); + float dist_pos = FLT_MAX; + float dist_neg = FLT_MAX; + float co_pos[2]; + float co_neg[2]; + float u; + + if (u_pos > 0.0f && u_pos < 1.0f) { + BKE_mask_point_segment_co(data->spline, data->point, u_pos, co_pos); + dist_pos = len_squared_v2v2(offco, co_pos); + } + + if (u_neg > 0.0f && u_neg < 1.0f) { + BKE_mask_point_segment_co(data->spline, data->point, u_neg, co_neg); + dist_neg = len_squared_v2v2(offco, co_neg); + } + + u = dist_pos < dist_neg ? u_pos : u_neg; if (u > 0.0f && u < 1.0f) { data->uw->u = u; @@ -1165,5 +1189,61 @@ void MASK_OT_hide_view_set(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected layers"); - +} + + +static int mask_feather_weight_clear_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Mask *mask = CTX_data_edit_mask(C); + MaskLayer *masklay; + int changed = FALSE; + int i; + + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + MaskSpline *spline; + + if (masklay->restrictflag & (MASK_RESTRICT_SELECT | MASK_RESTRICT_VIEW)) { + continue; + } + + for (spline = masklay->splines.first; spline; spline = spline->next) { + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &spline->points[i]; + + if (MASKPOINT_ISSEL_ANY(point)) { + BezTriple *bezt = &point->bezt; + bezt->weight = 0.0f; + changed = TRUE; + } + } + } + } + + if (changed) { + /* TODO: only update edited splines */ + BKE_mask_update_display(mask, CTX_data_scene(C)->r.cfra); + + WM_event_add_notifier(C, NC_MASK | ND_DRAW, mask); + DAG_id_tag_update(&mask->id, 0); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void MASK_OT_feather_weight_clear(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Clear Feather Weight"; + ot->description = "Reset the feather weight to zero"; + ot->idname = "MASK_OT_feather_weight_clear"; + + /* api callbacks */ + ot->exec = mask_feather_weight_clear_exec; + ot->poll = ED_maskedit_mask_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c index 1532e2e7199..51d370d5a88 100644 --- a/source/blender/makesrna/intern/rna_mask.c +++ b/source/blender/makesrna/intern/rna_mask.c @@ -583,7 +583,7 @@ static void rna_def_mask_layer(BlenderRNA *brna) prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "blend_flag", MASK_BLENDFLAG_INVERT); - RNA_def_property_ui_text(prop, "Restrict View", "Restrict visibility in the viewport"); + RNA_def_property_ui_text(prop, "Restrict View", "Invert the mask black/white"); RNA_def_property_update(prop, NC_MASK | NA_EDITED, NULL); }