Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2013-10-30 13:38:45 +0400
committerSergey Sharybin <sergey.vfx@gmail.com>2014-03-28 15:54:38 +0400
commit1af69b6df3c538bd329201520abaa5058a1ff0ca (patch)
tree9e926a25b1175d3ae61db584b2d5dde2dd9131e9 /source/blender/editors/mask
parent6e5e3b73f37f952420d87a3d8acd07a7f68dd5a3 (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/editors/mask')
-rw-r--r--source/blender/editors/mask/mask_add.c148
-rw-r--r--source/blender/editors/mask/mask_draw.c192
-rw-r--r--source/blender/editors/mask/mask_edit.c4
-rw-r--r--source/blender/editors/mask/mask_intern.h2
-rw-r--r--source/blender/editors/mask/mask_ops.c229
-rw-r--r--source/blender/editors/mask/mask_select.c30
6 files changed, 391 insertions, 214 deletions
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index 7fa41c361bb..2e1d5221b56 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -182,15 +182,13 @@ static int find_nearest_diff_point(const bContext *C, Mask *mask, const float no
/******************** add vertex *********************/
static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *new_point,
- const float point_co[2], const float tangent[2], const float u,
- MaskSplinePoint *reference_point, const short reference_adjacent,
- const float view_zoom)
+ const float point_co[2], const float u,
+ MaskSplinePoint *reference_point, const short reference_adjacent)
{
MaskSplinePoint *prev_point = NULL;
MaskSplinePoint *next_point = NULL;
BezTriple *bezt;
float co[3];
- const float len = 10.0; /* default length of handle in pixel space */
copy_v2_v2(co, point_co);
co[2] = 0.0f;
@@ -201,7 +199,41 @@ static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *
bezt->h1 = bezt->h2 = HD_ALIGN;
if (reference_point) {
- bezt->h1 = bezt->h2 = MAX2(reference_point->bezt.h2, reference_point->bezt.h1);
+ if (reference_point->bezt.h1 == HD_VECT && reference_point->bezt.h2 == HD_VECT) {
+ /* If the reference point is sharp try using some smooth point as reference
+ * for handles.
+ */
+ int point_index = reference_point - spline->points;
+ int delta = new_point == spline->points ? 1 : -1;
+ int i = 0;
+ for (i = 0; i < spline->tot_point - 1; ++i) {
+ MaskSplinePoint *current_point;
+
+ point_index += delta;
+ if (point_index == -1 || point_index >= spline->tot_point) {
+ if (spline->flag & MASK_SPLINE_CYCLIC) {
+ if (point_index == -1) {
+ point_index = spline->tot_point - 1;
+ }
+ else if (point_index >= spline->tot_point) {
+ point_index = 0;
+ }
+ }
+ else {
+ break;
+ }
+ }
+
+ current_point = &spline->points[point_index];
+ if (current_point->bezt.h1 != HD_VECT || current_point->bezt.h2 != HD_VECT) {
+ bezt->h1 = bezt->h2 = MAX2(current_point->bezt.h2, current_point->bezt.h1);
+ break;
+ }
+ }
+ }
+ else {
+ bezt->h1 = bezt->h2 = MAX2(reference_point->bezt.h2, reference_point->bezt.h1);
+ }
}
else if (reference_adjacent) {
if (spline->tot_point != 1) {
@@ -219,83 +251,11 @@ static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *
copy_v3_v3(bezt->vec[1], co);
copy_v3_v3(bezt->vec[2], co);
- /* initial offset for handles */
- if (spline->tot_point == 1) {
- /* first point of splien is aligned horizontally */
- bezt->vec[0][0] -= len * view_zoom;
- bezt->vec[2][0] += len * view_zoom;
- }
- else if (tangent) {
- float vec[2];
-
- copy_v2_v2(vec, tangent);
-
- mul_v2_fl(vec, len);
-
- sub_v2_v2(bezt->vec[0], vec);
- add_v2_v2(bezt->vec[2], vec);
-
- if (reference_adjacent) {
- BKE_mask_calc_handle_adjacent_interp(spline, new_point, u);
- }
- }
- else {
-
- /* calculating auto handles works much nicer */
-#if 0
- /* next points are aligning in the direction of previous/next point */
- MaskSplinePoint *point;
- float v1[2], v2[2], vec[2];
- float dir = 1.0f;
-
- if (new_point == spline->points) {
- point = new_point + 1;
- dir = -1.0f;
- }
- else
- point = new_point - 1;
-
- if (spline->tot_point < 3) {
- v1[0] = point->bezt.vec[1][0] * width;
- v1[1] = point->bezt.vec[1][1] * height;
-
- v2[0] = new_point->bezt.vec[1][0] * width;
- v2[1] = new_point->bezt.vec[1][1] * height;
- }
- else {
- if (new_point == spline->points) {
- v1[0] = spline->points[1].bezt.vec[1][0] * width;
- v1[1] = spline->points[1].bezt.vec[1][1] * height;
-
- v2[0] = spline->points[spline->tot_point - 1].bezt.vec[1][0] * width;
- v2[1] = spline->points[spline->tot_point - 1].bezt.vec[1][1] * height;
- }
- else {
- v1[0] = spline->points[0].bezt.vec[1][0] * width;
- v1[1] = spline->points[0].bezt.vec[1][1] * height;
-
- v2[0] = spline->points[spline->tot_point - 2].bezt.vec[1][0] * width;
- v2[1] = spline->points[spline->tot_point - 2].bezt.vec[1][1] * height;
- }
- }
-
- sub_v2_v2v2(vec, v1, v2);
- mul_v2_fl(vec, len * dir / len_v2(vec));
-
- vec[0] /= width;
- vec[1] /= height;
-
- add_v2_v2(bezt->vec[0], vec);
- sub_v2_v2(bezt->vec[2], vec);
-#else
- BKE_mask_calc_handle_point_auto(spline, new_point, TRUE);
+ BKE_mask_parent_init(&new_point->parent);
+ if (spline->tot_point != 1) {
BKE_mask_calc_handle_adjacent_interp(spline, new_point, u);
-
-#endif
}
- BKE_mask_parent_init(&new_point->parent);
-
/* select new point */
MASKPOINT_SEL_ALL(new_point);
ED_mask_select_flush_all(mask);
@@ -382,7 +342,7 @@ static int add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2]
new_point = &spline->points[point_index + 1];
- setup_vertex_point(mask, spline, new_point, co, tangent, u, NULL, TRUE, 1.0f);
+ setup_vertex_point(mask, spline, new_point, co, u, NULL, TRUE);
/* TODO - we could pass the spline! */
BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index + 1, true, true);
@@ -409,7 +369,6 @@ static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay,
float tangent_point[2];
float tangent_co[2];
bool do_cyclic_correct = false;
- bool do_recalc_src = false; /* when extruding from endpoints only */
bool do_prev; /* use prev point rather then next?? */
if (!masklay) {
@@ -440,11 +399,9 @@ static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay,
}
else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == 0)) {
do_prev = TRUE;
- do_recalc_src = TRUE;
}
else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == spline->tot_point - 1)) {
do_prev = FALSE;
- do_recalc_src = TRUE;
}
else {
do_prev = FALSE; /* quiet warning */
@@ -482,18 +439,13 @@ static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay,
masklay->act_point = new_point;
- setup_vertex_point(mask, spline, new_point, co, NULL, 0.5f, ref_point, FALSE, 1.0f);
+ setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, FALSE);
if (masklay->splines_shapes.first) {
point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index, true, true);
}
- if (do_recalc_src) {
- /* TODO, update keyframes in time */
- BKE_mask_calc_handle_point_auto(spline, ref_point, FALSE);
- }
-
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
return TRUE;
@@ -504,7 +456,6 @@ static int add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, con
MaskSpline *spline;
MaskSplinePoint *point;
MaskSplinePoint *new_point = NULL, *ref_point = NULL;
- float view_zoom;
if (!masklay) {
/* if there's no masklay currently operationg on, create new one */
@@ -529,22 +480,7 @@ static int add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, con
masklay->act_point = new_point;
- {
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
-
- float zoom_x, zoom_y;
- /* calc view zoom in a simplistic way */
- ED_mask_zoom(sa, ar, &zoom_x, &zoom_y);
-
- view_zoom = zoom_x + zoom_y / 2.0f;
- view_zoom = 1.0f / view_zoom;
-
- /* arbitrary but gives good results */
- view_zoom /= 500.0f;
- }
-
- setup_vertex_point(mask, spline, new_point, co, NULL, 0.5f, ref_point, FALSE, view_zoom);
+ setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, FALSE);
{
int point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 24fcbd19fc1..12fcd3c1459 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -132,29 +132,122 @@ static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float c
BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co);
}
+static void draw_circle(const float x, const float y,
+ const float size, const float xscale, const float yscale)
+{
+ static GLuint displist = 0;
+
+ /* Initialize round circle shape. */
+ if (displist == 0) {
+ GLUquadricObj *qobj;
+
+ displist = glGenLists(1);
+ glNewList(displist, GL_COMPILE);
+
+ qobj = gluNewQuadric();
+ gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
+ gluDisk(qobj, 0, 0.7, 8, 1);
+ gluDeleteQuadric(qobj);
+
+ glEndList();
+ }
+
+ glPushMatrix();
+ glTranslatef(x, y, 0.0f);
+ glScalef(1.0f / xscale * size, 1.0f / yscale * size, 1.0f);
+ glCallList(displist);
+ glPopMatrix();
+}
+
+static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoint *point,
+ const eMaskWhichHandle which_handle, const int draw_type,
+ const float handle_size, const float xscale, const float yscale,
+ const float point_pos[2], const float handle_pos[2])
+{
+ const BezTriple *bezt = &point->bezt;
+ char handle_type;
+
+ if (which_handle == MASK_WHICH_HANDLE_STICK || which_handle == MASK_WHICH_HANDLE_LEFT) {
+ handle_type = bezt->h1;
+ }
+ else {
+ handle_type = bezt->h2;
+ }
+
+ if (handle_type == HD_VECT) {
+ return;
+ }
+
+ /* this could be split into its own loop */
+ if (draw_type == MASK_DT_OUTLINE) {
+ const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
+ glLineWidth(3);
+ glColor4ubv(rgb_gray);
+ glBegin(GL_LINES);
+ glVertex2fv(point_pos);
+ glVertex2fv(handle_pos);
+ glEnd();
+ glLineWidth(1);
+ }
+
+ switch (handle_type) {
+ case HD_FREE:
+ UI_ThemeColor(TH_HANDLE_FREE);
+ break;
+ case HD_AUTO:
+ UI_ThemeColor(TH_HANDLE_AUTO);
+ break;
+ case HD_ALIGN:
+ case HD_ALIGN_DOUBLESIDE:
+ UI_ThemeColor(TH_HANDLE_ALIGN);
+ break;
+ }
+
+ glBegin(GL_LINES);
+ glVertex2fv(point_pos);
+ glVertex2fv(handle_pos);
+ glEnd();
+
+ /* draw handle points */
+ if (MASKPOINT_ISSEL_HANDLE(point, which_handle)) {
+ if (point == mask_layer->act_point)
+ glColor3f(1.0f, 1.0f, 1.0f);
+ else
+ glColor3f(1.0f, 1.0f, 0.0f);
+ }
+ else {
+ glColor3f(0.5f, 0.5f, 0.0f);
+ }
+
+ draw_circle(handle_pos[0], handle_pos[1], handle_size, xscale, yscale);
+}
+
/* return non-zero if spline is selected */
static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline *spline,
- const char UNUSED(draw_flag), const char draw_type)
+ const char draw_flag, const char draw_type,
+ const float xscale, const float yscale)
{
const bool is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
+ const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
+
unsigned char rgb_spline[4];
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
SpaceClip *sc = CTX_wm_space_clip(C);
- int undistort = FALSE;
+ bool undistort = false;
- int i, hsize, tot_feather_point;
+ int i, handle_size, tot_feather_point;
float (*feather_points)[2], (*fp)[2];
if (!spline->tot_point)
return;
if (sc)
- undistort = sc->clip && sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
+ undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0;
/* TODO, add this to sequence editor */
- hsize = 4; /* UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE); */
+ handle_size = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize;
- glPointSize(hsize);
+ glPointSize(handle_size);
mask_spline_color_get(masklay, spline, is_spline_sel, rgb_spline);
@@ -202,6 +295,12 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
}
MEM_freeN(feather_points);
+ if (is_smooth) {
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
/* control points */
for (i = 0; i < spline->tot_point; i++) {
@@ -210,38 +309,36 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
MaskSplinePoint *point_deform = &points_array[i];
BezTriple *bezt = &point_deform->bezt;
- float handle[2];
float vert[2];
- const bool has_handle = BKE_mask_point_has_handle(point);
copy_v2_v2(vert, bezt->vec[1]);
- BKE_mask_point_handle(point_deform, handle);
if (undistort) {
mask_point_undistort_pos(sc, vert, vert);
- mask_point_undistort_pos(sc, handle, handle);
}
/* draw handle segment */
- if (has_handle) {
-
- /* this could be split into its own loop */
- if (draw_type == MASK_DT_OUTLINE) {
- const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
- glLineWidth(3);
- glColor4ubv(rgb_gray);
- glBegin(GL_LINES);
- glVertex2fv(vert);
- glVertex2fv(handle);
- glEnd();
- glLineWidth(1);
+ if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+ float handle[2];
+ BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_STICK, handle);
+ if (undistort) {
+ mask_point_undistort_pos(sc, handle, handle);
}
-
- glColor3ubv(rgb_spline);
- glBegin(GL_LINES);
- glVertex2fv(vert);
- glVertex2fv(handle);
- glEnd();
+ draw_single_handle(masklay, point, MASK_WHICH_HANDLE_STICK,
+ draw_type, handle_size, xscale, yscale, vert, handle);
+ }
+ else {
+ float handle_left[2], handle_right[2];
+ BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_LEFT, handle_left);
+ BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_RIGHT, handle_right);
+ if (undistort) {
+ mask_point_undistort_pos(sc, handle_left, handle_left);
+ mask_point_undistort_pos(sc, handle_left, handle_left);
+ }
+ draw_single_handle(masklay, point, MASK_WHICH_HANDLE_LEFT,
+ draw_type, handle_size, xscale, yscale, vert, handle_left);
+ draw_single_handle(masklay, point, MASK_WHICH_HANDLE_RIGHT,
+ draw_type, handle_size, xscale, yscale, vert, handle_right);
}
/* draw CV point */
@@ -257,26 +354,14 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
glBegin(GL_POINTS);
glVertex2fv(vert);
glEnd();
-
- /* draw handle points */
- if (has_handle) {
- if (MASKPOINT_ISSEL_HANDLE(point)) {
- if (point == masklay->act_point)
- glColor3f(1.0f, 1.0f, 1.0f);
- else
- glColor3f(1.0f, 1.0f, 0.0f);
- }
- else {
- glColor3f(0.5f, 0.5f, 0.0f);
- }
-
- glBegin(GL_POINTS);
- glVertex2fv(handle);
- glEnd();
- }
}
glPointSize(1.0f);
+
+ if (is_smooth) {
+ glDisable(GL_LINE_SMOOTH);
+ glDisable(GL_BLEND);
+ }
}
/* #define USE_XOR */
@@ -408,7 +493,7 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline *spline,
const char draw_flag, const char draw_type,
const bool is_active,
- int width, int height)
+ const int width, const int height)
{
const unsigned int resol = max_ii(BKE_mask_spline_feather_resolution(spline, width, height),
BKE_mask_spline_resolution(spline, width, height));
@@ -482,7 +567,7 @@ static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline
}
static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, const char draw_type,
- int width, int height)
+ const int width, const int height, const float xscale, const float yscale)
{
MaskLayer *masklay;
int i;
@@ -504,7 +589,7 @@ static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, c
if (!(masklay->restrictflag & MASK_RESTRICT_SELECT)) {
/* ...and then handles over the curve so they're nicely visible */
- draw_spline_points(C, masklay, spline, draw_flag, draw_type);
+ draw_spline_points(C, masklay, spline, draw_flag, draw_type, xscale, yscale);
}
/* show undeform for testing */
@@ -514,7 +599,7 @@ static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, c
spline->points_deform = NULL;
draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
// draw_spline_parents(masklay, spline);
- draw_spline_points(C, masklay, spline, draw_flag, draw_type);
+ draw_spline_points(C, masklay, spline, draw_flag, draw_type, xscale, yscale);
spline->points_deform = back;
}
}
@@ -525,16 +610,21 @@ void ED_mask_draw(const bContext *C,
const char draw_flag, const char draw_type)
{
ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
int width, height;
+ float aspx, aspy;
+ float xscale, yscale;
if (!mask)
return;
ED_mask_get_size(sa, &width, &height);
+ ED_mask_get_aspect(sa, ar, &aspx, &aspy);
+ UI_view2d_getscale(&ar->v2d, &xscale, &yscale);
- draw_masklays(C, mask, draw_flag, draw_type, width, height);
+ draw_masklays(C, mask, draw_flag, draw_type, width, height, xscale * aspx, yscale * aspy);
}
typedef struct ThreadedMaskRasterizeState {
@@ -719,7 +809,7 @@ void ED_mask_draw_region(Mask *mask, ARegion *ar,
}
/* draw! */
- draw_masklays(C, mask, draw_flag, draw_type, width, height);
+ draw_masklays(C, mask, draw_flag, draw_type, width, height, maxdim * zoomx, maxdim * zoomy);
if (do_draw_cb) {
ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c
index ad287a3af9f..af4645e31ec 100644
--- a/source/blender/editors/mask/mask_edit.c
+++ b/source/blender/editors/mask/mask_edit.c
@@ -570,8 +570,8 @@ void ED_operatormacros_mask(void)
"Add new vertex and slide it", OPTYPE_UNDO | OPTYPE_REGISTER);
ot->description = "Add new vertex and slide it";
WM_operatortype_macro_define(ot, "MASK_OT_add_vertex");
- otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
- RNA_boolean_set(otmacro->ptr, "release_confirm", TRUE);
+ otmacro = WM_operatortype_macro_define(ot, "MASK_OT_slide_point");
+ RNA_boolean_set(otmacro->ptr, "is_new_point", TRUE);
ot = WM_operatortype_append_macro("MASK_OT_add_feather_vertex_slide", "Add Feather Vertex and Slide",
"Add new vertex to feather and slide it", OPTYPE_UNDO | OPTYPE_REGISTER);
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index 62872e72cb4..d95e07f043a 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -73,7 +73,7 @@ bool ED_mask_feather_find_nearest(
struct MaskSplinePoint *ED_mask_point_find_nearest(
const struct bContext *C, struct Mask *mask, const float normal_co[2], const float threshold,
- struct MaskLayer **masklay_r, struct MaskSpline **spline_r, bool *is_handle_r,
+ struct MaskLayer **masklay_r, struct MaskSpline **spline_r, eMaskWhichHandle *which_handle_r,
float *score);
void MASK_OT_layer_move(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index b9b456177ea..da91c59a094 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -59,9 +59,17 @@
/******************** utility functions *********************/
+static void mask_point_scaled_handle(/*const*/ MaskSplinePoint *point, /*const*/ eMaskWhichHandle which_handle,
+ const float scalex, const float scaley, float handle[2])
+{
+ BKE_mask_point_handle(point, which_handle, handle);
+ handle[0] *= scalex;
+ handle[1] *= scaley;
+}
+
MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const float normal_co[2], const float threshold,
- MaskLayer **masklay_r, MaskSpline **spline_r, bool *is_handle_r,
- float *score)
+ MaskLayer **masklay_r, MaskSpline **spline_r,
+ eMaskWhichHandle *which_handle_r, float *score)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
@@ -72,8 +80,9 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const
MaskSplinePoint *point = NULL;
float co[2];
const float threshold_sq = threshold * threshold;
- float len_sq = FLT_MAX, scalex, scaley;
- int is_handle = FALSE, width, height;
+ float len_sq= FLT_MAX, scalex, scaley;
+ eMaskWhichHandle which_handle = MASK_WHICH_HANDLE_NONE;
+ int width, height;
ED_mask_get_size(sa, &width, &height);
ED_mask_pixelspace_factor(sa, ar, &scalex, &scaley);
@@ -96,35 +105,64 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *cur_point = &spline->points[i];
MaskSplinePoint *cur_point_deform = &points_array[i];
- float cur_len_sq, vec[2], handle[2];
+ eMaskWhichHandle cur_which_handle;
+ float cur_len_sq, vec[2];
vec[0] = cur_point_deform->bezt.vec[1][0] * scalex;
vec[1] = cur_point_deform->bezt.vec[1][1] * scaley;
- if (BKE_mask_point_has_handle(cur_point)) {
- BKE_mask_point_handle(cur_point_deform, handle);
- handle[0] *= scalex;
- handle[1] *= scaley;
+ cur_len_sq = len_squared_v2v2(co, vec);
- cur_len_sq = len_squared_v2v2(co, handle);
+ if (cur_len_sq < len_sq) {
+ point_spline = spline;
+ point_masklay = masklay;
+ point = cur_point;
+ len_sq = cur_len_sq;
+ which_handle = MASK_WHICH_HANDLE_NONE;
+ }
- if (cur_len_sq < len_sq) {
- point_masklay = masklay;
- point_spline = spline;
- point = cur_point;
- len_sq = cur_len_sq;
- is_handle = TRUE;
+ if (BKE_mask_point_handles_mode_get(cur_point_deform) == MASK_HANDLE_MODE_STICK) {
+ float handle[2];
+ mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_STICK, scalex, scaley, handle);
+ cur_len_sq = len_squared_v2v2(co, handle);
+ cur_which_handle = MASK_WHICH_HANDLE_STICK;
+ }
+ else {
+ float handle_left[2], handle_right[2];
+ float len_left_sq, len_right_sq;
+ mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_LEFT, scalex, scaley, handle_left);
+ mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_RIGHT, scalex, scaley, handle_right);
+
+ len_left_sq = len_squared_v2v2(co, handle_left);
+ len_right_sq = len_squared_v2v2(co, handle_right);
+ if (i == 0) {
+ if (len_left_sq <= len_right_sq) {
+ cur_which_handle = MASK_WHICH_HANDLE_LEFT;
+ cur_len_sq = len_left_sq;
+ }
+ else {
+ cur_which_handle = MASK_WHICH_HANDLE_RIGHT;
+ cur_len_sq = len_right_sq;
+ }
+ }
+ else {
+ if (len_right_sq <= len_left_sq) {
+ cur_which_handle = MASK_WHICH_HANDLE_RIGHT;
+ cur_len_sq = len_right_sq;
+ }
+ else {
+ cur_which_handle = MASK_WHICH_HANDLE_LEFT;
+ cur_len_sq = len_left_sq;
+ }
}
}
- cur_len_sq = len_squared_v2v2(co, vec);
-
- if (cur_len_sq < len_sq) {
- point_spline = spline;
+ if (cur_len_sq <= len_sq) {
point_masklay = masklay;
+ point_spline = spline;
point = cur_point;
len_sq = cur_len_sq;
- is_handle = FALSE;
+ which_handle = cur_which_handle;
}
}
}
@@ -137,8 +175,8 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const
if (spline_r)
*spline_r = point_spline;
- if (is_handle_r)
- *is_handle_r = is_handle;
+ if (which_handle_r)
+ *which_handle_r = which_handle;
if (score)
*score = sqrtf(len_sq);
@@ -152,8 +190,8 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const
if (spline_r)
*spline_r = NULL;
- if (is_handle_r)
- *is_handle_r = FALSE;
+ if (which_handle_r)
+ *which_handle_r = MASK_WHICH_HANDLE_NONE;
return NULL;
}
@@ -423,18 +461,22 @@ typedef struct SlidePointData {
float co[2];
float vec[3][3];
+ char old_h1, old_h2;
Mask *mask;
MaskLayer *masklay;
MaskSpline *spline, *orig_spline;
MaskSplinePoint *point;
MaskSplinePointUW *uw;
+ eMaskWhichHandle which_handle;
float handle[2], no[2], feather[2];
int width, height;
float weight, weight_scalar;
short curvature_only, accurate;
short initial_feather, overall_feather;
+
+ bool is_sliding_new_point;
} SlidePointData;
static bool slide_point_check_initial_feather(MaskSpline *spline)
@@ -460,6 +502,41 @@ static bool slide_point_check_initial_feather(MaskSpline *spline)
return TRUE;
}
+static void select_sliding_point(Mask *mask, MaskLayer *mask_layer, MaskSpline *spline,
+ MaskSplinePoint *point)
+{
+ ED_mask_select_toggle_all(mask, SEL_DESELECT);
+ BKE_mask_point_select_set(point, TRUE);
+
+ mask_layer->act_spline = spline;
+ mask_layer->act_point = point;
+ ED_mask_select_flush_all(mask);
+}
+
+static void check_sliding_handle_type(MaskSplinePoint *point, eMaskWhichHandle which_handle)
+{
+ BezTriple *bezt = &point->bezt;
+
+ if (which_handle == MASK_WHICH_HANDLE_LEFT) {
+ if (bezt->h1 == HD_VECT) {
+ bezt->h1 = HD_FREE;
+ }
+ else if (bezt->h1 == HD_AUTO) {
+ bezt->h1 = HD_ALIGN_DOUBLESIDE;
+ bezt->h2 = HD_ALIGN_DOUBLESIDE;
+ }
+ }
+ else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
+ if (bezt->h2 == HD_VECT) {
+ bezt->h2 = HD_FREE;
+ }
+ else if (bezt->h2 == HD_AUTO) {
+ bezt->h1 = HD_ALIGN_DOUBLESIDE;
+ bezt->h2 = HD_ALIGN_DOUBLESIDE;
+ }
+ }
+}
+
static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *event)
{
ScrArea *sa = CTX_wm_area(C);
@@ -472,15 +549,15 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
MaskSplinePoint *point, *cv_point, *feather_point;
MaskSplinePointUW *uw = NULL;
int width, height, action = SLIDE_ACTION_NONE;
- bool is_handle = false;
const bool slide_feather = RNA_boolean_get(op->ptr, "slide_feather");
float co[2], cv_score, feather_score;
const float threshold = 19;
+ eMaskWhichHandle which_handle;
ED_mask_mouse_pos(sa, ar, event->mval, co);
ED_mask_get_size(sa, &width, &height);
- cv_point = ED_mask_point_find_nearest(C, mask, co, threshold, &cv_masklay, &cv_spline, &is_handle, &cv_score);
+ cv_point = ED_mask_point_find_nearest(C, mask, co, threshold, &cv_masklay, &cv_spline, &which_handle, &cv_score);
if (ED_mask_feather_find_nearest(C, mask, co, threshold, &feather_masklay, &feather_spline, &feather_point, &uw, &feather_score)) {
if (slide_feather || !cv_point || feather_score < cv_score) {
@@ -493,7 +570,7 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
}
if (cv_point && action == SLIDE_ACTION_NONE) {
- if (is_handle)
+ if (which_handle != MASK_WHICH_HANDLE_NONE)
action = SLIDE_ACTION_HANDLE;
else
action = SLIDE_ACTION_POINT;
@@ -504,6 +581,8 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
}
if (action != SLIDE_ACTION_NONE) {
+ select_sliding_point(mask, masklay, spline, point);
+
customdata = MEM_callocN(sizeof(SlidePointData), "mask slide point data");
customdata->mask = mask;
@@ -515,6 +594,13 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
customdata->action = action;
customdata->uw = uw;
+ customdata->old_h1 = point->bezt.h1;
+ customdata->old_h2 = point->bezt.h2;
+
+ customdata->is_sliding_new_point = RNA_boolean_get(op->ptr, "is_new_point");
+
+ check_sliding_handle_type(point, which_handle);
+
if (uw) {
float co_uw[2];
float weight_scalar = BKE_mask_point_weight_scalar(spline, point, uw->u);
@@ -540,8 +626,10 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
customdata->initial_feather = slide_point_check_initial_feather(spline);
copy_m3_m3(customdata->vec, point->bezt.vec);
- if (BKE_mask_point_has_handle(point))
- BKE_mask_point_handle(point, customdata->handle);
+ if (which_handle != MASK_WHICH_HANDLE_NONE) {
+ BKE_mask_point_handle(point, which_handle, customdata->handle);
+ }
+ customdata->which_handle = which_handle;
ED_mask_mouse_pos(sa, ar, event->mval, customdata->co);
}
@@ -550,11 +638,16 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
static int slide_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- SlidePointData *slidedata = slide_point_customdata(C, op, event);
+ Mask *mask = CTX_data_edit_mask(C);
+ SlidePointData *slidedata;
- if (slidedata) {
- Mask *mask = CTX_data_edit_mask(C);
+ if (mask == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+ slidedata = slide_point_customdata(C, op, event);
+
+ if (slidedata) {
op->customdata = slidedata;
WM_event_add_modal_handler(C, op);
@@ -645,6 +738,8 @@ static void cancel_slide_point(SlidePointData *data)
}
else {
copy_m3_m3(data->point->bezt.vec, data->vec);
+ data->point->bezt.h1 = data->old_h1;
+ data->point->bezt.h2 = data->old_h2;
}
}
}
@@ -695,10 +790,34 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
sub_v2_v2v2(offco, co, data->co);
if (data->accurate)
mul_v2_fl(offco, 0.2f);
+
+ if (data->is_sliding_new_point && data->which_handle == MASK_WHICH_HANDLE_STICK) {
+ if (ELEM(data->point, &data->spline->points[0],
+ &data->spline->points[data->spline->tot_point - 1]))
+ {
+ SWAP(float, offco[0], offco[1]);
+ offco[1] *= -1;
+ }
+ }
+
add_v2_v2(offco, data->co);
add_v2_v2(offco, delta);
- BKE_mask_point_set_handle(data->point, offco, data->curvature_only, data->handle, data->vec);
+ BKE_mask_point_set_handle(data->point, data->which_handle,
+ offco, data->curvature_only,
+ data->handle, data->vec);
+
+ if (data->is_sliding_new_point) {
+ if (ELEM(data->which_handle, MASK_WHICH_HANDLE_LEFT, MASK_WHICH_HANDLE_RIGHT)) {
+ BezTriple *bezt = &data->point->bezt;
+ float vec[2];
+ short self_handle = (data->which_handle == MASK_WHICH_HANDLE_LEFT) ? 0 : 2;
+ short other_handle = (data->which_handle == MASK_WHICH_HANDLE_LEFT) ? 2 : 0;
+
+ sub_v2_v2v2(vec, bezt->vec[1], bezt->vec[self_handle]);
+ add_v2_v2v2(bezt->vec[other_handle], bezt->vec[1], vec);
+ }
+ }
}
else if (data->action == SLIDE_ACTION_POINT) {
float delta[2];
@@ -826,6 +945,16 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
+ if (data->is_sliding_new_point) {
+ BezTriple *bezt = &data->point->bezt;
+ if (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) < FLT_EPSILON) {
+ bezt->h1 = HD_VECT;
+ }
+ if (len_squared_v2v2(bezt->vec[2], bezt->vec[1]) < FLT_EPSILON) {
+ bezt->h2 = HD_VECT;
+ }
+ }
+
WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
DAG_id_tag_update(&data->mask->id, 0);
@@ -850,6 +979,8 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
void MASK_OT_slide_point(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Slide Point";
ot->description = "Slide control points";
@@ -858,12 +989,15 @@ void MASK_OT_slide_point(wmOperatorType *ot)
/* api callbacks */
ot->invoke = slide_point_invoke;
ot->modal = slide_point_modal;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_operator_mask;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "slide_feather", 0, "Slide Feather", "First try to slide feather instead of vertex");
+
+ prop = RNA_def_boolean(ot->srna, "is_new_point", 0, "Slide New Point", "Newly created vertex is being slided");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/******************** toggle cyclic *********************/
@@ -887,6 +1021,7 @@ static int cyclic_toggle_exec(bContext *C, wmOperator *UNUSED(op))
}
}
+ DAG_id_tag_update(&mask->id, 0);
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
return OPERATOR_FINISHED;
@@ -1218,7 +1353,25 @@ static int set_handle_type_exec(bContext *C, wmOperator *op)
if (MASKPOINT_ISSEL_ANY(point)) {
BezTriple *bezt = &point->bezt;
- bezt->h1 = bezt->h2 = handle_type;
+ if (bezt->f2 & SELECT) {
+ bezt->h1 = handle_type;
+ bezt->h2 = handle_type;
+ }
+ else {
+ if (bezt->f1 & SELECT) {
+ bezt->h1 = handle_type;
+ }
+ if (bezt->f3 & SELECT) {
+ bezt->h2 = handle_type;
+ }
+ }
+
+ if (handle_type == HD_ALIGN) {
+ float vec[3];
+ sub_v3_v3v3(vec, bezt->vec[0], bezt->vec[1]);
+ add_v3_v3v3(bezt->vec[2], bezt->vec[1], vec);
+ }
+
changed = true;
}
}
@@ -1239,7 +1392,9 @@ void MASK_OT_handle_type_set(wmOperatorType *ot)
static EnumPropertyItem editcurve_handle_type_items[] = {
{HD_AUTO, "AUTO", 0, "Auto", ""},
{HD_VECT, "VECTOR", 0, "Vector", ""},
- {HD_ALIGN, "ALIGNED", 0, "Aligned", ""},
+ {HD_ALIGN, "ALIGNED", 0, "Aligned Single", ""},
+ {HD_ALIGN_DOUBLESIDE, "ALIGNED_DOUBLESIDE", 0, "Aligned", ""},
+ {HD_FREE, "FREE", 0, "Free", ""},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index 16fd8414f22..29b5714be59 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -255,38 +255,36 @@ static int select_exec(bContext *C, wmOperator *op)
bool extend = RNA_boolean_get(op->ptr, "extend");
bool deselect = RNA_boolean_get(op->ptr, "deselect");
bool toggle = RNA_boolean_get(op->ptr, "toggle");
-
- bool is_handle = 0;
+ eMaskWhichHandle which_handle;
const float threshold = 19;
RNA_float_get_array(op->ptr, "location", co);
- point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, &is_handle, NULL);
+ point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, &which_handle, NULL);
if (extend == false && deselect == false && toggle == false)
ED_mask_select_toggle_all(mask, SEL_DESELECT);
if (point) {
-
- if (is_handle) {
+ if (which_handle != MASK_WHICH_HANDLE_NONE) {
if (extend) {
masklay->act_spline = spline;
masklay->act_point = point;
- BKE_mask_point_select_set_handle(point, TRUE);
+ BKE_mask_point_select_set_handle(point, which_handle, TRUE);
}
else if (deselect) {
- BKE_mask_point_select_set_handle(point, FALSE);
+ BKE_mask_point_select_set_handle(point, which_handle, FALSE);
}
else {
masklay->act_spline = spline;
masklay->act_point = point;
- if (!MASKPOINT_ISSEL_HANDLE(point)) {
- BKE_mask_point_select_set_handle(point, TRUE);
+ if (!MASKPOINT_ISSEL_HANDLE(point, which_handle)) {
+ BKE_mask_point_select_set_handle(point, which_handle, TRUE);
}
else if (toggle) {
- BKE_mask_point_select_set_handle(point, FALSE);
+ BKE_mask_point_select_set_handle(point, which_handle, FALSE);
}
}
}
@@ -444,11 +442,11 @@ static int border_select_exec(bContext *C, wmOperator *op)
if (BLI_rctf_isect_pt_v(&rectf, point_deform->bezt.vec[1])) {
BKE_mask_point_select_set(point, mode == GESTURE_MODAL_SELECT);
- BKE_mask_point_select_set_handle(point, mode == GESTURE_MODAL_SELECT);
+ BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, mode == GESTURE_MODAL_SELECT);
}
else if (!extend) {
BKE_mask_point_select_set(point, FALSE);
- BKE_mask_point_select_set_handle(point, FALSE);
+ BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, FALSE);
}
changed = true;
@@ -531,7 +529,7 @@ static bool do_lasso_select_mask(bContext *C, const int mcords[][2], short moves
BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX))
{
BKE_mask_point_select_set(point, select);
- BKE_mask_point_select_set_handle(point, select);
+ BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, select);
}
changed = true;
@@ -649,7 +647,7 @@ static int circle_select_exec(bContext *C, wmOperator *op)
if (mask_spline_point_inside_ellipse(&point_deform->bezt, offset, ellipse)) {
BKE_mask_point_select_set(point, mode == GESTURE_MODAL_SELECT);
- BKE_mask_point_select_set_handle(point, mode == GESTURE_MODAL_SELECT);
+ BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, mode == GESTURE_MODAL_SELECT);
changed = true;
}
@@ -702,14 +700,12 @@ static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
MaskSplinePoint *point = NULL;
float co[2];
int do_select = !RNA_boolean_get(op->ptr, "deselect");
-
- bool is_handle = false;
const float threshold = 19;
bool changed = false;
ED_mask_mouse_pos(sa, ar, event->mval, co);
- point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, &is_handle, NULL);
+ point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, NULL, NULL);
if (point) {
ED_mask_spline_select_set(spline, do_select);