diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2014-08-19 19:27:12 +0400 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2014-08-19 19:29:45 +0400 |
commit | 09fc5d6a37803d57051bb6a923fb1fcc96985edf (patch) | |
tree | b361eabcabd70b1f36e6d9ef751f1b3265af4242 /source/blender/editors | |
parent | 7bc87a372e40b6adc852d42c60ea6aca55aaa7fb (diff) |
Roto: Add spline dragging zone in it's center
This dragging zone is visualized as the circle (the same as object origin)
in the spline bounding box center and dragging that circle drags the whole
spline.
Pretty much basic functionality, but quite useful in practice.
Requested by our roto team (Sebastian and Sean :) in IRC.
Diffstat (limited to 'source/blender/editors')
-rw-r--r-- | source/blender/editors/mask/mask_draw.c | 39 | ||||
-rw-r--r-- | source/blender/editors/mask/mask_ops.c | 140 |
2 files changed, 162 insertions, 17 deletions
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c index c2b949f6acb..94092036cb9 100644 --- a/source/blender/editors/mask/mask_draw.c +++ b/source/blender/editors/mask/mask_draw.c @@ -133,9 +133,12 @@ static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float c } static void draw_circle(const float x, const float y, - const float size, const float xscale, const float yscale) + const float size, const bool fill, + const float xscale, const float yscale) { - static GLuint displist = 0; + static GLuint wire_displist = 0; + static GLuint fill_displist = 0; + GLuint displist = fill ? fill_displist : wire_displist; /* Initialize round circle shape. */ if (displist == 0) { @@ -145,11 +148,18 @@ static void draw_circle(const float x, const float y, glNewList(displist, GL_COMPILE); qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); + gluQuadricDrawStyle(qobj, fill ? GLU_FILL : GLU_SILHOUETTE); gluDisk(qobj, 0, 0.7, 8, 1); gluDeleteQuadric(qobj); glEndList(); + + if (fill) { + fill_displist = displist; + } + else { + wire_displist = displist; + } } glPushMatrix(); @@ -219,7 +229,7 @@ static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoin UI_ThemeColor(TH_HANDLE_VERTEX); } - draw_circle(handle_pos[0], handle_pos[1], handle_size, xscale, yscale); + draw_circle(handle_pos[0], handle_pos[1], handle_size, false, xscale, yscale); } /* return non-zero if spline is selected */ @@ -237,6 +247,7 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline int i, handle_size, tot_feather_point; float (*feather_points)[2], (*fp)[2]; + float min[2], max[2]; if (!spline->tot_point) return; @@ -302,6 +313,7 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline } /* control points */ + INIT_MINMAX2(min, max); for (i = 0; i < spline->tot_point; i++) { /* watch it! this is intentionally not the deform array, only check for sel */ @@ -354,6 +366,25 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline glBegin(GL_POINTS); glVertex2fv(vert); glEnd(); + + minmax_v2v2_v2(min, max, vert); + } + + if (is_spline_sel) { + float x = (min[0] + max[0]) / 2.0f; + float y = (min[1] + max[1]) / 2.0f; + /* TODO(sergey): Remove hardcoded colors. */ + if (masklay->act_spline == spline) { + glColor3ub(255, 255, 255); + } + else { + glColor3ub(255, 255, 0); + } + + draw_circle(x, y, 6.0f, true, xscale, yscale); + + glColor3ub(0, 0, 0); + draw_circle(x, y, 6.0f, false, xscale, yscale); } glPointSize(1.0f); diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index c9eacc898b5..9f8388f1fe0 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -458,7 +458,8 @@ enum { SLIDE_ACTION_NONE = 0, SLIDE_ACTION_POINT = 1, SLIDE_ACTION_HANDLE = 2, - SLIDE_ACTION_FEATHER = 3 + SLIDE_ACTION_FEATHER = 3, + SLIDE_ACTION_SPLINE = 4 }; typedef struct SlidePointData { @@ -497,6 +498,96 @@ typedef struct SlidePointData { float weight, weight_scalar; } SlidePointData; +static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float co[2]) +{ + BKE_mask_coord_to_movieclip(sc->clip, &sc->user, r_co, co); + ED_clip_point_undistorted_pos(sc, r_co, r_co); + BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co); +} + +static bool spline_under_mouse_get(const bContext *C, + Mask *mask, const float co[2], + MaskLayer **mask_layer_r, + MaskSpline **mask_spline_r) +{ + ScrArea *sa = CTX_wm_area(C); + SpaceClip *sc = CTX_wm_space_clip(C); + MaskLayer *mask_layer; + int width, height; + float pixel_co[2]; + float closest_dist_squared; + MaskLayer *closest_layer = NULL; + MaskSpline *closest_spline = NULL; + bool undistort = false; + *mask_layer_r = NULL; + *mask_spline_r = NULL; + ED_mask_get_size(sa, &width, &height); + pixel_co[0] = co[0] * width; + pixel_co[1] = co[1] * height; + if (sc != NULL) { + undistort = (sc->clip != NULL) && + (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0; + } + for (mask_layer = mask->masklayers.first; + mask_layer != NULL; + mask_layer = mask_layer->next) + { + MaskSpline *spline; + if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) { + continue; + } + + for (spline = mask_layer->splines.first; + spline != NULL; + spline = spline->next) + { + MaskSplinePoint *points_array; + float min[2], max[2], center[2]; + float dist_squared; + int i; + float max_bb_side; + if ((spline->flag & SELECT) == 0) { + continue; + } + + points_array = BKE_mask_spline_point_array(spline); + INIT_MINMAX2(min, max); + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point_deform = &points_array[i]; + BezTriple *bezt = &point_deform->bezt; + + float vert[2]; + + copy_v2_v2(vert, bezt->vec[1]); + + if (undistort) { + mask_point_undistort_pos(sc, vert, vert); + } + + minmax_v2v2_v2(min, max, vert); + } + + center[0] = (min[0] + max[0]) / 2.0f * width; + center[1] = (min[1] + max[1]) / 2.0f * height; + dist_squared = len_squared_v2v2(pixel_co, center); + max_bb_side = min_ff((max[0] - min[0]) * width, (max[1] - min[1]) * height); + if (dist_squared <= max_bb_side * max_bb_side * 0.5f && + (closest_spline == NULL || dist_squared < closest_dist_squared)) + { + closest_layer = mask_layer; + closest_spline = spline; + closest_dist_squared = dist_squared; + } + } + } + if (closest_spline != NULL) { + *mask_layer_r = closest_layer; + *mask_spline_r = closest_spline; + return true; + } + return false; +} + static bool slide_point_check_initial_feather(MaskSpline *spline) { int i; @@ -607,9 +698,14 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * point = cv_point; } - if (action != SLIDE_ACTION_NONE) { - select_sliding_point(mask, masklay, spline, point, which_handle); + if (action == SLIDE_ACTION_NONE) { + if (spline_under_mouse_get(C, mask, co, &masklay, &spline)) { + action = SLIDE_ACTION_SPLINE; + point = NULL; + } + } + if (action != SLIDE_ACTION_NONE) { customdata = MEM_callocN(sizeof(SlidePointData), "mask slide point data"); customdata->event_invoke_type = event->type; customdata->mask = mask; @@ -621,12 +717,14 @@ 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 (customdata->action != SLIDE_ACTION_SPLINE) { + customdata->old_h1 = point->bezt.h1; + customdata->old_h2 = point->bezt.h2; + select_sliding_point(mask, masklay, spline, point, which_handle); + check_sliding_handle_type(point, which_handle); + } if (uw) { float co_uw[2]; @@ -639,7 +737,7 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * madd_v2_v2v2fl(customdata->prev_feather_coord, co_uw, customdata->no, uw->w * weight_scalar); } - else { + else if (customdata->action != SLIDE_ACTION_SPLINE) { BezTriple *bezt = &point->bezt; customdata->weight = bezt->weight; @@ -653,10 +751,12 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * customdata->is_initial_feather = slide_point_check_initial_feather(spline); } - copy_m3_m3(customdata->vec, point->bezt.vec); - if (which_handle != MASK_WHICH_HANDLE_NONE) { - BKE_mask_point_handle(point, which_handle, customdata->orig_handle_coord); - copy_v2_v2(customdata->prev_handle_coord, customdata->orig_handle_coord); + if (customdata->action != SLIDE_ACTION_SPLINE) { + copy_m3_m3(customdata->vec, point->bezt.vec); + if (which_handle != MASK_WHICH_HANDLE_NONE) { + BKE_mask_point_handle(point, which_handle, customdata->orig_handle_coord); + copy_v2_v2(customdata->prev_handle_coord, customdata->orig_handle_coord); + } } customdata->which_handle = which_handle; @@ -738,7 +838,7 @@ static void cancel_slide_point(SlidePointData *data) else data->point->bezt.weight = data->weight; } - else { + else if (data->action != SLIDE_ACTION_SPLINE) { copy_m3_m3(data->point->bezt.vec, data->vec); data->point->bezt.h1 = data->old_h1; data->point->bezt.h2 = data->old_h2; @@ -935,6 +1035,20 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event) copy_v2_v2(data->prev_feather_coord, offco); } } + else if (data->action == SLIDE_ACTION_SPLINE) { + int i; + + if (data->orig_spline == NULL) { + data->orig_spline = BKE_mask_spline_copy(data->spline); + } + + for (i = 0; i < data->spline->tot_point; i++) { + MaskSplinePoint *point = &data->spline->points[i]; + add_v2_v2(point->bezt.vec[0], delta); + add_v2_v2(point->bezt.vec[1], delta); + add_v2_v2(point->bezt.vec[2], delta); + } + } WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask); DAG_id_tag_update(&data->mask->id, 0); |