doxygen: add newline after \file
[blender.git] / source / blender / editors / mask / mask_ops.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2012 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edmask
22  */
23
24 #include "MEM_guardedalloc.h"
25
26 #include "BLI_listbase.h"
27 #include "BLI_math.h"
28
29 #include "BKE_context.h"
30 #include "BKE_main.h"
31 #include "BKE_mask.h"
32
33 #include "DEG_depsgraph.h"
34
35 #include "DNA_scene_types.h"
36 #include "DNA_mask_types.h"
37 #include "DNA_object_types.h"  /* SELECT */
38
39 #include "WM_api.h"
40 #include "WM_types.h"
41
42 #include "ED_clip.h"
43 #include "ED_image.h"
44 #include "ED_keyframing.h"
45 #include "ED_mask.h"
46 #include "ED_screen.h"
47 #include "ED_select_utils.h"
48
49 #include "RNA_access.h"
50 #include "RNA_define.h"
51
52 #include "mask_intern.h"  /* own include */
53
54 /******************** utility functions *********************/
55
56 static void mask_point_scaled_handle(/*const*/ MaskSplinePoint *point, /*const*/ eMaskWhichHandle which_handle,
57                                      const float scalex, const float scaley, float handle[2])
58 {
59         BKE_mask_point_handle(point, which_handle, handle);
60         handle[0] *= scalex;
61         handle[1] *= scaley;
62 }
63
64 MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const float normal_co[2], const float threshold,
65                                             MaskLayer **masklay_r, MaskSpline **spline_r,
66                                             eMaskWhichHandle *which_handle_r, float *score)
67 {
68         ScrArea *sa = CTX_wm_area(C);
69         ARegion *ar = CTX_wm_region(C);
70
71         MaskLayer *masklay;
72         MaskLayer *point_masklay = NULL;
73         MaskSpline *point_spline = NULL;
74         MaskSplinePoint *point = NULL;
75         float co[2];
76         const float threshold_sq = threshold * threshold;
77         float len_sq = FLT_MAX, scalex, scaley;
78         eMaskWhichHandle which_handle = MASK_WHICH_HANDLE_NONE;
79         int width, height;
80
81         ED_mask_get_size(sa, &width, &height);
82         ED_mask_pixelspace_factor(sa, ar, &scalex, &scaley);
83
84         co[0] = normal_co[0] * scalex;
85         co[1] = normal_co[1] * scaley;
86
87         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
88                 MaskSpline *spline;
89
90                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
91                         continue;
92                 }
93
94                 for (spline = masklay->splines.first; spline; spline = spline->next) {
95                         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
96
97                         int i;
98
99                         for (i = 0; i < spline->tot_point; i++) {
100                                 MaskSplinePoint *cur_point = &spline->points[i];
101                                 MaskSplinePoint *cur_point_deform = &points_array[i];
102                                 eMaskWhichHandle cur_which_handle = MASK_WHICH_HANDLE_NONE;
103                                 BezTriple *bezt = &cur_point_deform->bezt;
104                                 float cur_len_sq, vec[2];
105
106                                 vec[0] = bezt->vec[1][0] * scalex;
107                                 vec[1] = bezt->vec[1][1] * scaley;
108
109                                 cur_len_sq = len_squared_v2v2(co, vec);
110
111                                 if (cur_len_sq < len_sq) {
112                                         point_spline = spline;
113                                         point_masklay = masklay;
114                                         point = cur_point;
115                                         len_sq = cur_len_sq;
116                                         which_handle = MASK_WHICH_HANDLE_NONE;
117                                 }
118
119                                 if (BKE_mask_point_handles_mode_get(cur_point_deform) == MASK_HANDLE_MODE_STICK) {
120                                         float handle[2];
121                                         mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_STICK, scalex, scaley, handle);
122                                         cur_len_sq = len_squared_v2v2(co, handle);
123                                         cur_which_handle = MASK_WHICH_HANDLE_STICK;
124                                 }
125                                 else {
126                                         float handle_left[2], handle_right[2];
127                                         float len_left_sq, len_right_sq;
128                                         mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_LEFT, scalex, scaley, handle_left);
129                                         mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_RIGHT, scalex, scaley, handle_right);
130
131                                         len_left_sq = len_squared_v2v2(co, handle_left);
132                                         len_right_sq = len_squared_v2v2(co, handle_right);
133                                         if (i == 0) {
134                                                 if (len_left_sq <= len_right_sq) {
135                                                         if (bezt->h1 != HD_VECT) {
136                                                                 cur_which_handle = MASK_WHICH_HANDLE_LEFT;
137                                                                 cur_len_sq = len_left_sq;
138                                                         }
139                                                 }
140                                                 else if (bezt->h2 != HD_VECT) {
141                                                         cur_which_handle = MASK_WHICH_HANDLE_RIGHT;
142                                                         cur_len_sq = len_right_sq;
143                                                 }
144                                         }
145                                         else {
146                                                 if (len_right_sq <= len_left_sq) {
147                                                         if (bezt->h2 != HD_VECT) {
148                                                                 cur_which_handle = MASK_WHICH_HANDLE_RIGHT;
149                                                                 cur_len_sq = len_right_sq;
150                                                         }
151                                                 }
152                                                 else if (bezt->h1 != HD_VECT) {
153                                                         cur_which_handle = MASK_WHICH_HANDLE_LEFT;
154                                                         cur_len_sq = len_left_sq;
155                                                 }
156                                         }
157                                 }
158
159                                 if (cur_len_sq <= len_sq && cur_which_handle != MASK_WHICH_HANDLE_NONE) {
160                                         point_masklay = masklay;
161                                         point_spline = spline;
162                                         point = cur_point;
163                                         len_sq = cur_len_sq;
164                                         which_handle = cur_which_handle;
165                                 }
166                         }
167                 }
168         }
169
170         if (len_sq < threshold_sq) {
171                 if (masklay_r)
172                         *masklay_r = point_masklay;
173
174                 if (spline_r)
175                         *spline_r = point_spline;
176
177                 if (which_handle_r)
178                         *which_handle_r = which_handle;
179
180                 if (score)
181                         *score = sqrtf(len_sq);
182
183                 return point;
184         }
185
186         if (masklay_r)
187                 *masklay_r = NULL;
188
189         if (spline_r)
190                 *spline_r = NULL;
191
192         if (which_handle_r)
193                 *which_handle_r = MASK_WHICH_HANDLE_NONE;
194
195         return NULL;
196 }
197
198 bool ED_mask_feather_find_nearest(const bContext *C, Mask *mask, const float normal_co[2], const float threshold,
199                                   MaskLayer **masklay_r, MaskSpline **spline_r, MaskSplinePoint **point_r,
200                                   MaskSplinePointUW **uw_r, float *score)
201 {
202         ScrArea *sa = CTX_wm_area(C);
203         ARegion *ar = CTX_wm_region(C);
204
205         MaskLayer *masklay, *point_masklay = NULL;
206         MaskSpline *point_spline = NULL;
207         MaskSplinePoint *point = NULL;
208         MaskSplinePointUW *uw = NULL;
209         const float threshold_sq = threshold * threshold;
210         float len = FLT_MAX, co[2];
211         float scalex, scaley;
212         int width, height;
213
214         ED_mask_get_size(sa, &width, &height);
215         ED_mask_pixelspace_factor(sa, ar, &scalex, &scaley);
216
217         co[0] = normal_co[0] * scalex;
218         co[1] = normal_co[1] * scaley;
219
220         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
221                 MaskSpline *spline;
222
223                 for (spline = masklay->splines.first; spline; spline = spline->next) {
224                         //MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
225
226                         int i, tot_feather_point;
227                         float (*feather_points)[2], (*fp)[2];
228
229                         if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
230                                 continue;
231                         }
232
233                         feather_points = fp = BKE_mask_spline_feather_points(spline, &tot_feather_point);
234
235                         for (i = 0; i < spline->tot_point; i++) {
236                                 int j;
237                                 MaskSplinePoint *cur_point = &spline->points[i];
238
239                                 for (j = 0; j <= cur_point->tot_uw; j++) {
240                                         float cur_len_sq, vec[2];
241
242                                         vec[0] = (*fp)[0] * scalex;
243                                         vec[1] = (*fp)[1] * scaley;
244
245                                         cur_len_sq = len_squared_v2v2(vec, co);
246
247                                         if (point == NULL || cur_len_sq < len) {
248                                                 if (j == 0)
249                                                         uw = NULL;
250                                                 else
251                                                         uw = &cur_point->uw[j - 1];
252
253                                                 point_masklay = masklay;
254                                                 point_spline = spline;
255                                                 point = cur_point;
256                                                 len = cur_len_sq;
257                                         }
258
259                                         fp++;
260                                 }
261                         }
262
263                         MEM_freeN(feather_points);
264                 }
265         }
266
267         if (len < threshold_sq) {
268                 if (masklay_r)
269                         *masklay_r = point_masklay;
270
271                 if (spline_r)
272                         *spline_r = point_spline;
273
274                 if (point_r)
275                         *point_r = point;
276
277                 if (uw_r)
278                         *uw_r = uw;
279
280                 if (score)
281                         *score = sqrtf(len);
282
283                 return true;
284         }
285
286         if (masklay_r)
287                 *masklay_r = NULL;
288
289         if (spline_r)
290                 *spline_r = NULL;
291
292         if (point_r)
293                 *point_r = NULL;
294
295         return false;
296 }
297
298
299 /******************** create new mask *********************/
300
301 Mask *ED_mask_new(bContext *C, const char *name)
302 {
303         ScrArea *sa = CTX_wm_area(C);
304         Main *bmain = CTX_data_main(C);
305         Mask *mask;
306
307         mask = BKE_mask_new(bmain, name);
308
309         if (sa && sa->spacedata.first) {
310                 switch (sa->spacetype) {
311                         case SPACE_CLIP:
312                         {
313                                 SpaceClip *sc = sa->spacedata.first;
314                                 ED_space_clip_set_mask(C, sc, mask);
315                                 break;
316                         }
317                         case SPACE_SEQ:
318                         {
319                                 /* do nothing */
320                                 break;
321                         }
322                         case SPACE_IMAGE:
323                         {
324                                 SpaceImage *sima = sa->spacedata.first;
325                                 ED_space_image_set_mask(C, sima, mask);
326                                 break;
327                         }
328                 }
329         }
330
331         return mask;
332 }
333
334 /* Get ative layer. Will create mask/layer to be sure there's an active layer.  */
335 MaskLayer *ED_mask_layer_ensure(bContext *C, bool *r_added_mask)
336 {
337         Mask *mask = CTX_data_edit_mask(C);
338         MaskLayer *mask_layer;
339
340         if (mask == NULL) {
341                 /* If there's no active mask, create one. */
342                 mask = ED_mask_new(C, NULL);
343                 *r_added_mask = true;
344         }
345
346         mask_layer = BKE_mask_layer_active(mask);
347         if (mask_layer == NULL) {
348                 /* If there's no active mask layer, create one. */
349                 mask_layer = BKE_mask_layer_new(mask, "");
350         }
351
352         return mask_layer;
353 }
354
355 static int mask_new_exec(bContext *C, wmOperator *op)
356 {
357         char name[MAX_ID_NAME - 2];
358
359         RNA_string_get(op->ptr, "name", name);
360
361         ED_mask_new(C, name);
362
363         WM_event_add_notifier(C, NC_MASK | NA_ADDED, NULL);
364
365         return OPERATOR_FINISHED;
366 }
367
368 void MASK_OT_new(wmOperatorType *ot)
369 {
370         /* identifiers */
371         ot->name = "New Mask";
372         ot->description = "Create new mask";
373         ot->idname = "MASK_OT_new";
374
375         /* flags */
376         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
377
378         /* api callbacks */
379         ot->exec = mask_new_exec;
380         ot->poll = ED_operator_mask;
381
382         /* properties */
383         RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Name of new mask");
384 }
385
386 /******************** create new masklay *********************/
387
388 static int masklay_new_exec(bContext *C, wmOperator *op)
389 {
390         Mask *mask = CTX_data_edit_mask(C);
391         char name[MAX_ID_NAME - 2];
392
393         RNA_string_get(op->ptr, "name", name);
394
395         BKE_mask_layer_new(mask, name);
396         mask->masklay_act = mask->masklay_tot - 1;
397
398         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
399
400         return OPERATOR_FINISHED;
401 }
402
403 void MASK_OT_layer_new(wmOperatorType *ot)
404 {
405         /* identifiers */
406         ot->name = "Add Mask Layer";
407         ot->description = "Add new mask layer for masking";
408         ot->idname = "MASK_OT_layer_new";
409
410         /* api callbacks */
411         ot->exec = masklay_new_exec;
412         ot->poll = ED_maskedit_poll;
413
414         /* flags */
415         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
416
417         /* properties */
418         RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Name of new mask layer");
419 }
420
421 /******************** remove mask layer *********************/
422
423 static int masklay_remove_exec(bContext *C, wmOperator *UNUSED(op))
424 {
425         Mask *mask = CTX_data_edit_mask(C);
426         MaskLayer *masklay = BKE_mask_layer_active(mask);
427
428         if (masklay) {
429                 BKE_mask_layer_remove(mask, masklay);
430
431                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
432         }
433
434         return OPERATOR_FINISHED;
435 }
436
437 void MASK_OT_layer_remove(wmOperatorType *ot)
438 {
439         /* identifiers */
440         ot->name = "Remove Mask Layer";
441         ot->description = "Remove mask layer";
442         ot->idname = "MASK_OT_layer_remove";
443
444         /* api callbacks */
445         ot->exec = masklay_remove_exec;
446         ot->poll = ED_maskedit_poll;
447
448         /* flags */
449         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
450 }
451
452 /******************** slide *********************/
453
454 enum {
455         SLIDE_ACTION_NONE    = 0,
456         SLIDE_ACTION_POINT   = 1,
457         SLIDE_ACTION_HANDLE  = 2,
458         SLIDE_ACTION_FEATHER = 3,
459         SLIDE_ACTION_SPLINE  = 4,
460 };
461
462 typedef struct SlidePointData {
463         /* Generic fields. */
464         short event_invoke_type;
465         int action;
466         Mask *mask;
467         MaskLayer *masklay;
468         MaskSpline *spline, *orig_spline;
469         MaskSplinePoint *point;
470         MaskSplinePointUW *uw;
471         eMaskWhichHandle which_handle;
472         int width, height;
473
474         float prev_mouse_coord[2];
475         float no[2];
476
477         bool is_curvature_only,
478              is_accurate,
479              is_initial_feather,
480              is_overall_feather;
481
482         bool is_sliding_new_point;
483
484         /* Data needed to restre the state. */
485         float vec[3][3];
486         char old_h1, old_h2;
487
488         /* Point sliding. */
489
490         /* Handle sliding. */
491         float orig_handle_coord[2], prev_handle_coord[2];
492
493         /* Feather sliding. */
494         float prev_feather_coord[2];
495         float weight, weight_scalar;
496 } SlidePointData;
497
498 static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float co[2])
499 {
500         BKE_mask_coord_to_movieclip(sc->clip, &sc->user, r_co, co);
501         ED_clip_point_undistorted_pos(sc, r_co, r_co);
502         BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co);
503 }
504
505 static bool spline_under_mouse_get(const bContext *C,
506                                    Mask *mask, const float co[2],
507                                    MaskLayer **mask_layer_r,
508                                    MaskSpline **mask_spline_r)
509 {
510         const float threshold = 19.0f;
511         ScrArea *sa = CTX_wm_area(C);
512         SpaceClip *sc = CTX_wm_space_clip(C);
513         MaskLayer *mask_layer;
514         int width, height;
515         float pixel_co[2];
516         float closest_dist_squared = 0.0f;
517         MaskLayer *closest_layer = NULL;
518         MaskSpline *closest_spline = NULL;
519         bool undistort = false;
520         *mask_layer_r = NULL;
521         *mask_spline_r = NULL;
522         ED_mask_get_size(sa, &width, &height);
523         pixel_co[0] = co[0] * width;
524         pixel_co[1] = co[1] * height;
525         if (sc != NULL) {
526                 undistort = (sc->clip != NULL) &&
527                             (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0;
528         }
529         for (mask_layer = mask->masklayers.first;
530              mask_layer != NULL;
531              mask_layer = mask_layer->next)
532         {
533                 MaskSpline *spline;
534                 if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) {
535                         continue;
536                 }
537
538                 for (spline = mask_layer->splines.first;
539                      spline != NULL;
540                      spline = spline->next)
541                 {
542                         MaskSplinePoint *points_array;
543                         float min[2], max[2], center[2];
544                         float dist_squared;
545                         int i;
546                         float max_bb_side;
547                         if ((spline->flag & SELECT) == 0) {
548                                 continue;
549                         }
550
551                         points_array = BKE_mask_spline_point_array(spline);
552                         INIT_MINMAX2(min, max);
553                         for (i = 0; i < spline->tot_point; i++) {
554                                 MaskSplinePoint *point_deform = &points_array[i];
555                                 BezTriple *bezt = &point_deform->bezt;
556
557                                 float vert[2];
558
559                                 copy_v2_v2(vert, bezt->vec[1]);
560
561                                 if (undistort) {
562                                         mask_point_undistort_pos(sc, vert, vert);
563                                 }
564
565                                 minmax_v2v2_v2(min, max, vert);
566                         }
567
568                         center[0] = (min[0] + max[0]) / 2.0f * width;
569                         center[1] = (min[1] + max[1]) / 2.0f * height;
570                         dist_squared = len_squared_v2v2(pixel_co, center);
571                         max_bb_side = min_ff((max[0] - min[0]) * width, (max[1] - min[1]) * height);
572                         if (dist_squared <= max_bb_side * max_bb_side * 0.5f &&
573                             (closest_spline == NULL || dist_squared < closest_dist_squared))
574                         {
575                                 closest_layer = mask_layer;
576                                 closest_spline = spline;
577                                 closest_dist_squared = dist_squared;
578                         }
579                 }
580         }
581         if (closest_dist_squared < SQUARE(threshold) && closest_spline != NULL) {
582                 float diff_score;
583                 if (ED_mask_find_nearest_diff_point(C, mask, co, threshold,
584                                                     false, NULL, true, false,
585                                                     NULL, NULL, NULL, NULL,
586                                                     &diff_score))
587                 {
588                         if (SQUARE(diff_score) < closest_dist_squared) {
589                                 return false;
590                         }
591                 }
592
593                 *mask_layer_r = closest_layer;
594                 *mask_spline_r = closest_spline;
595                 return true;
596         }
597         return false;
598 }
599
600 static bool slide_point_check_initial_feather(MaskSpline *spline)
601 {
602         int i;
603
604         for (i = 0; i < spline->tot_point; i++) {
605                 MaskSplinePoint *point = &spline->points[i];
606
607                 if (point->bezt.weight != 0.0f) {
608                         return false;
609                 }
610         }
611
612         return true;
613 }
614
615 static void select_sliding_point(Mask *mask, MaskLayer *mask_layer, MaskSpline *spline,
616                                  MaskSplinePoint *point, eMaskWhichHandle which_handle)
617 {
618         ED_mask_select_toggle_all(mask, SEL_DESELECT);
619
620         switch (which_handle) {
621                 case MASK_WHICH_HANDLE_NONE:
622                         BKE_mask_point_select_set(point, true);
623                         break;
624                 case MASK_WHICH_HANDLE_LEFT:
625                         point->bezt.f1 |= SELECT;
626                         break;
627                 case MASK_WHICH_HANDLE_RIGHT:
628                         point->bezt.f3 |= SELECT;
629                         break;
630                 case MASK_WHICH_HANDLE_STICK:
631                         point->bezt.f1 |= SELECT;
632                         point->bezt.f3 |= SELECT;
633                         break;
634                 default:
635                         BLI_assert(!"Unexpected situation in select_sliding_point()");
636         }
637
638         mask_layer->act_spline = spline;
639         mask_layer->act_point = point;
640         ED_mask_select_flush_all(mask);
641 }
642
643 static void check_sliding_handle_type(MaskSplinePoint *point, eMaskWhichHandle which_handle)
644 {
645         BezTriple *bezt = &point->bezt;
646
647         if (which_handle == MASK_WHICH_HANDLE_LEFT) {
648                 if (bezt->h1 == HD_VECT) {
649                         bezt->h1 = HD_FREE;
650                 }
651                 else if (bezt->h1 == HD_AUTO) {
652                         bezt->h1 = HD_ALIGN_DOUBLESIDE;
653                         bezt->h2 = HD_ALIGN_DOUBLESIDE;
654                 }
655         }
656         else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
657                 if (bezt->h2 == HD_VECT) {
658                         bezt->h2 = HD_FREE;
659                 }
660                 else if (bezt->h2 == HD_AUTO) {
661                         bezt->h1 = HD_ALIGN_DOUBLESIDE;
662                         bezt->h2 = HD_ALIGN_DOUBLESIDE;
663                 }
664         }
665 }
666
667 static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *event)
668 {
669         ScrArea *sa = CTX_wm_area(C);
670         ARegion *ar = CTX_wm_region(C);
671
672         Mask *mask = CTX_data_edit_mask(C);
673         SlidePointData *customdata = NULL;
674         MaskLayer *masklay, *cv_masklay, *feather_masklay;
675         MaskSpline *spline, *cv_spline, *feather_spline;
676         MaskSplinePoint *point, *cv_point, *feather_point;
677         MaskSplinePointUW *uw = NULL;
678         int width, height, action = SLIDE_ACTION_NONE;
679         const bool slide_feather = RNA_boolean_get(op->ptr, "slide_feather");
680         float co[2], cv_score, feather_score;
681         const float threshold = 19;
682         eMaskWhichHandle which_handle;
683
684         ED_mask_mouse_pos(sa, ar, event->mval, co);
685         ED_mask_get_size(sa, &width, &height);
686
687         cv_point = ED_mask_point_find_nearest(C, mask, co, threshold, &cv_masklay, &cv_spline, &which_handle, &cv_score);
688
689         if (ED_mask_feather_find_nearest(C, mask, co, threshold, &feather_masklay, &feather_spline, &feather_point, &uw, &feather_score)) {
690                 if (slide_feather || !cv_point || feather_score < cv_score) {
691                         action = SLIDE_ACTION_FEATHER;
692
693                         masklay = feather_masklay;
694                         spline = feather_spline;
695                         point = feather_point;
696                 }
697         }
698
699         if (cv_point && action == SLIDE_ACTION_NONE) {
700                 if (which_handle != MASK_WHICH_HANDLE_NONE)
701                         action = SLIDE_ACTION_HANDLE;
702                 else
703                         action = SLIDE_ACTION_POINT;
704
705                 masklay = cv_masklay;
706                 spline = cv_spline;
707                 point = cv_point;
708         }
709
710         if (action == SLIDE_ACTION_NONE) {
711                 if (spline_under_mouse_get(C, mask, co, &masklay, &spline)) {
712                         action = SLIDE_ACTION_SPLINE;
713                         point = NULL;
714                 }
715         }
716
717         if (action != SLIDE_ACTION_NONE) {
718                 customdata = MEM_callocN(sizeof(SlidePointData), "mask slide point data");
719                 customdata->event_invoke_type = event->type;
720                 customdata->mask = mask;
721                 customdata->masklay = masklay;
722                 customdata->spline = spline;
723                 customdata->point = point;
724                 customdata->width = width;
725                 customdata->height = height;
726                 customdata->action = action;
727                 customdata->uw = uw;
728
729                 customdata->is_sliding_new_point = RNA_boolean_get(op->ptr, "is_new_point");
730
731                 if (customdata->action != SLIDE_ACTION_SPLINE) {
732                         customdata->old_h1 = point->bezt.h1;
733                         customdata->old_h2 = point->bezt.h2;
734                         select_sliding_point(mask, masklay, spline, point, which_handle);
735                         check_sliding_handle_type(point, which_handle);
736                 }
737
738                 if (uw) {
739                         float co_uw[2];
740                         float weight_scalar = BKE_mask_point_weight_scalar(spline, point, uw->u);
741
742                         customdata->weight = uw->w;
743                         customdata->weight_scalar = weight_scalar;
744                         BKE_mask_point_segment_co(spline, point, uw->u, co_uw);
745                         BKE_mask_point_normal(spline, point, uw->u, customdata->no);
746
747                         madd_v2_v2v2fl(customdata->prev_feather_coord, co_uw, customdata->no, uw->w * weight_scalar);
748                 }
749                 else if (customdata->action != SLIDE_ACTION_SPLINE) {
750                         BezTriple *bezt = &point->bezt;
751
752                         customdata->weight = bezt->weight;
753                         customdata->weight_scalar = 1.0f;
754                         BKE_mask_point_normal(spline, point, 0.0f, customdata->no);
755
756                         madd_v2_v2v2fl(customdata->prev_feather_coord, bezt->vec[1], customdata->no, bezt->weight);
757                 }
758
759                 if (customdata->action == SLIDE_ACTION_FEATHER) {
760                         customdata->is_initial_feather = slide_point_check_initial_feather(spline);
761                 }
762
763                 if (customdata->action != SLIDE_ACTION_SPLINE) {
764                         copy_m3_m3(customdata->vec, point->bezt.vec);
765                         if (which_handle != MASK_WHICH_HANDLE_NONE) {
766                                 BKE_mask_point_handle(point, which_handle, customdata->orig_handle_coord);
767                                 copy_v2_v2(customdata->prev_handle_coord, customdata->orig_handle_coord);
768                         }
769                 }
770                 customdata->which_handle = which_handle;
771
772                 ED_mask_mouse_pos(sa, ar, event->mval, customdata->prev_mouse_coord);
773         }
774
775         return customdata;
776 }
777
778 static int slide_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
779 {
780         Mask *mask = CTX_data_edit_mask(C);
781         SlidePointData *slidedata;
782
783         if (mask == NULL) {
784                 return OPERATOR_PASS_THROUGH;
785         }
786
787         slidedata = slide_point_customdata(C, op, event);
788
789         if (slidedata) {
790                 op->customdata = slidedata;
791
792                 WM_event_add_modal_handler(C, op);
793
794                 slidedata->masklay->act_spline = slidedata->spline;
795                 slidedata->masklay->act_point = slidedata->point;
796
797                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
798
799                 return OPERATOR_RUNNING_MODAL;
800         }
801
802         return OPERATOR_PASS_THROUGH;
803 }
804
805 static void slide_point_delta_all_feather(SlidePointData *data, float delta)
806 {
807         int i;
808
809         for (i = 0; i < data->spline->tot_point; i++) {
810                 MaskSplinePoint *point = &data->spline->points[i];
811                 MaskSplinePoint *orig_point = &data->orig_spline->points[i];
812
813                 point->bezt.weight = orig_point->bezt.weight + delta;
814                 if (point->bezt.weight < 0.0f) {
815                         point->bezt.weight = 0.0f;
816                 }
817         }
818 }
819
820 static void slide_point_restore_spline(SlidePointData *data)
821 {
822         int i;
823
824         for (i = 0; i < data->spline->tot_point; i++) {
825                 MaskSplinePoint *point = &data->spline->points[i];
826                 MaskSplinePoint *orig_point = &data->orig_spline->points[i];
827                 int j;
828
829                 point->bezt = orig_point->bezt;
830
831                 for (j = 0; j < point->tot_uw; j++)
832                         point->uw[j] = orig_point->uw[j];
833         }
834 }
835
836 static void cancel_slide_point(SlidePointData *data)
837 {
838         /* cancel sliding */
839
840         if (data->orig_spline) {
841                 slide_point_restore_spline(data);
842         }
843         else {
844                 if (data->action == SLIDE_ACTION_FEATHER) {
845                         if (data->uw)
846                                 data->uw->w = data->weight;
847                         else
848                                 data->point->bezt.weight = data->weight;
849                 }
850                 else if (data->action != SLIDE_ACTION_SPLINE) {
851                         copy_m3_m3(data->point->bezt.vec, data->vec);
852                         data->point->bezt.h1 = data->old_h1;
853                         data->point->bezt.h2 = data->old_h2;
854                 }
855         }
856 }
857
858 static void free_slide_point_data(SlidePointData *data)
859 {
860         if (data->orig_spline)
861                 BKE_mask_spline_free(data->orig_spline);
862
863         MEM_freeN(data);
864 }
865
866 static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
867 {
868         SlidePointData *data = (SlidePointData *)op->customdata;
869         BezTriple *bezt = &data->point->bezt;
870         float co[2];
871
872         switch (event->type) {
873                 case LEFTALTKEY:
874                 case RIGHTALTKEY:
875                 case LEFTSHIFTKEY:
876                 case RIGHTSHIFTKEY:
877                         if (ELEM(event->type, LEFTALTKEY, RIGHTALTKEY)) {
878                                 if (data->action == SLIDE_ACTION_FEATHER) {
879                                         data->is_overall_feather = (event->val == KM_PRESS);
880                                 }
881                                 else {
882                                         data->is_curvature_only = (event->val == KM_PRESS);
883                                 }
884                         }
885
886                         if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
887                                 data->is_accurate = (event->val == KM_PRESS);
888
889                         ATTR_FALLTHROUGH;  /* update CV position */
890                 case MOUSEMOVE:
891                 {
892                         ScrArea *sa = CTX_wm_area(C);
893                         ARegion *ar = CTX_wm_region(C);
894                         float delta[2];
895
896                         ED_mask_mouse_pos(sa, ar, event->mval, co);
897                         sub_v2_v2v2(delta, co, data->prev_mouse_coord);
898                         if (data->is_accurate) {
899                                 mul_v2_fl(delta, 0.2f);
900                         }
901                         copy_v2_v2(data->prev_mouse_coord, co);
902
903                         if (data->action == SLIDE_ACTION_HANDLE) {
904                                 float new_handle[2];
905
906                                 if (data->is_sliding_new_point && data->which_handle == MASK_WHICH_HANDLE_STICK) {
907                                         if (ELEM(data->point, &data->spline->points[0],
908                                                               &data->spline->points[data->spline->tot_point - 1]))
909                                         {
910                                                 SWAP(float, delta[0], delta[1]);
911                                                 delta[1] *= -1;
912
913                                                 /* flip last point */
914                                                 if (data->point != &data->spline->points[0]) {
915                                                         negate_v2(delta);
916                                                 }
917                                         }
918                                 }
919
920                                 add_v2_v2v2(new_handle, data->prev_handle_coord, delta);
921
922                                 BKE_mask_point_set_handle(data->point, data->which_handle,
923                                                           new_handle, data->is_curvature_only,
924                                                           data->orig_handle_coord, data->vec);
925                                 BKE_mask_point_handle(data->point, data->which_handle, data->prev_handle_coord);
926
927                                 if (data->is_sliding_new_point) {
928                                         if (ELEM(data->which_handle, MASK_WHICH_HANDLE_LEFT, MASK_WHICH_HANDLE_RIGHT)) {
929                                                 float vec[2];
930                                                 short self_handle = (data->which_handle == MASK_WHICH_HANDLE_LEFT) ? 0 : 2;
931                                                 short other_handle = (data->which_handle == MASK_WHICH_HANDLE_LEFT) ? 2 : 0;
932
933                                                 sub_v2_v2v2(vec, bezt->vec[1], bezt->vec[self_handle]);
934                                                 add_v2_v2v2(bezt->vec[other_handle], bezt->vec[1], vec);
935                                         }
936                                 }
937                         }
938                         else if (data->action == SLIDE_ACTION_POINT) {
939                                 add_v2_v2(bezt->vec[0], delta);
940                                 add_v2_v2(bezt->vec[1], delta);
941                                 add_v2_v2(bezt->vec[2], delta);
942                         }
943                         else if (data->action == SLIDE_ACTION_FEATHER) {
944                                 float vec[2], no[2], p[2], c[2], w, offco[2];
945                                 float *weight = NULL;
946                                 float weight_scalar = 1.0f;
947                                 bool is_overall_feather = data->is_overall_feather || data->is_initial_feather;
948
949                                 add_v2_v2v2(offco, data->prev_feather_coord, delta);
950
951                                 if (data->uw) {
952                                         /* project on both sides and find the closest one,
953                                          * prevents flickering when projecting onto both sides can happen */
954                                         const float u_pos = BKE_mask_spline_project_co(data->spline, data->point,
955                                                                                        data->uw->u, offco, MASK_PROJ_NEG);
956                                         const float u_neg = BKE_mask_spline_project_co(data->spline, data->point,
957                                                                                        data->uw->u, offco, MASK_PROJ_POS);
958                                         float dist_pos = FLT_MAX;
959                                         float dist_neg = FLT_MAX;
960                                         float co_pos[2];
961                                         float co_neg[2];
962                                         float u;
963
964                                         if (u_pos > 0.0f && u_pos < 1.0f) {
965                                                 BKE_mask_point_segment_co(data->spline, data->point, u_pos, co_pos);
966                                                 dist_pos = len_squared_v2v2(offco, co_pos);
967                                         }
968
969                                         if (u_neg > 0.0f && u_neg < 1.0f) {
970                                                 BKE_mask_point_segment_co(data->spline, data->point, u_neg, co_neg);
971                                                 dist_neg = len_squared_v2v2(offco, co_neg);
972                                         }
973
974                                         u = dist_pos < dist_neg ? u_pos : u_neg;
975
976                                         if (u > 0.0f && u < 1.0f) {
977                                                 data->uw->u = u;
978
979                                                 data->uw = BKE_mask_point_sort_uw(data->point, data->uw);
980                                                 weight = &data->uw->w;
981                                                 weight_scalar = BKE_mask_point_weight_scalar(data->spline, data->point, u);
982                                                 if (weight_scalar != 0.0f) {
983                                                         weight_scalar = 1.0f / weight_scalar;
984                                                 }
985
986                                                 BKE_mask_point_normal(data->spline, data->point, data->uw->u, no);
987                                                 BKE_mask_point_segment_co(data->spline, data->point, data->uw->u, p);
988                                         }
989                                 }
990                                 else {
991                                         weight = &bezt->weight;
992                                         /* weight_scalar = 1.0f; keep as is */
993                                         copy_v2_v2(no, data->no);
994                                         copy_v2_v2(p, bezt->vec[1]);
995                                 }
996
997                                 if (weight) {
998                                         sub_v2_v2v2(c, offco, p);
999                                         project_v2_v2v2_normalized(vec, c, no);
1000
1001                                         w = len_v2(vec);
1002
1003                                         if (is_overall_feather) {
1004                                                 float w_delta;
1005
1006                                                 if (dot_v2v2(no, vec) <= 0.0f)
1007                                                         w = -w;
1008
1009                                                 w_delta = w - data->weight * data->weight_scalar;
1010
1011                                                 if (data->orig_spline == NULL) {
1012                                                         /* restore weight for currently sliding point, so orig_spline would be created
1013                                                          * with original weights used
1014                                                          */
1015                                                         *weight = data->weight;
1016
1017                                                         data->orig_spline = BKE_mask_spline_copy(data->spline);
1018                                                 }
1019
1020                                                 if (data->is_initial_feather) {
1021                                                         *weight = w * weight_scalar;
1022                                                 }
1023
1024                                                 slide_point_delta_all_feather(data, w_delta);
1025                                         }
1026                                         else {
1027                                                 if (dot_v2v2(no, vec) <= 0.0f)
1028                                                         w = 0.0f;
1029
1030                                                 if (data->orig_spline) {
1031                                                         /* restore possible overall feather changes */
1032                                                         slide_point_restore_spline(data);
1033
1034                                                         BKE_mask_spline_free(data->orig_spline);
1035                                                         data->orig_spline = NULL;
1036                                                 }
1037
1038                                                 if (weight_scalar != 0.0f) {
1039                                                         *weight = w * weight_scalar;
1040                                                 }
1041                                         }
1042
1043                                         copy_v2_v2(data->prev_feather_coord, offco);
1044                                 }
1045                         }
1046                         else if (data->action == SLIDE_ACTION_SPLINE) {
1047                                 int i;
1048
1049                                 if (data->orig_spline == NULL) {
1050                                         data->orig_spline = BKE_mask_spline_copy(data->spline);
1051                                 }
1052
1053                                 for (i = 0; i < data->spline->tot_point; i++) {
1054                                         MaskSplinePoint *point = &data->spline->points[i];
1055                                         add_v2_v2(point->bezt.vec[0], delta);
1056                                         add_v2_v2(point->bezt.vec[1], delta);
1057                                         add_v2_v2(point->bezt.vec[2], delta);
1058                                 }
1059                         }
1060
1061                         WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
1062                         DEG_id_tag_update(&data->mask->id, 0);
1063
1064                         break;
1065                 }
1066
1067                 case LEFTMOUSE:
1068                 case RIGHTMOUSE:
1069                         if (event->type == data->event_invoke_type && event->val == KM_RELEASE) {
1070                                 Scene *scene = CTX_data_scene(C);
1071
1072                                 /* dont key sliding feather uw's */
1073                                 if ((data->action == SLIDE_ACTION_FEATHER && data->uw) == false) {
1074                                         if (IS_AUTOKEY_ON(scene)) {
1075                                                 ED_mask_layer_shape_auto_key(data->masklay, CFRA);
1076                                         }
1077                                 }
1078
1079                                 if (data->is_sliding_new_point) {
1080                                         if (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) < FLT_EPSILON) {
1081                                                 bezt->h1 = HD_VECT;
1082                                         }
1083                                         if (len_squared_v2v2(bezt->vec[2], bezt->vec[1]) < FLT_EPSILON) {
1084                                                 bezt->h2 = HD_VECT;
1085                                         }
1086                                 }
1087
1088                                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
1089                                 DEG_id_tag_update(&data->mask->id, 0);
1090
1091                                 free_slide_point_data(op->customdata); /* keep this last! */
1092                                 return OPERATOR_FINISHED;
1093                         }
1094                         else if (event->type != data->event_invoke_type && event->val == KM_PRESS) {
1095                                 /* pass to ESCKEY */
1096                         }
1097                         else {
1098                                 break;
1099                         }
1100
1101                 case ESCKEY:
1102                         cancel_slide_point(op->customdata);
1103
1104                         WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
1105                         DEG_id_tag_update(&data->mask->id, 0);
1106
1107                         free_slide_point_data(op->customdata); /* keep this last! */
1108                         return OPERATOR_CANCELLED;
1109         }
1110
1111         return OPERATOR_RUNNING_MODAL;
1112 }
1113
1114 void MASK_OT_slide_point(wmOperatorType *ot)
1115 {
1116         PropertyRNA *prop;
1117
1118         /* identifiers */
1119         ot->name = "Slide Point";
1120         ot->description = "Slide control points";
1121         ot->idname = "MASK_OT_slide_point";
1122
1123         /* api callbacks */
1124         ot->invoke = slide_point_invoke;
1125         ot->modal = slide_point_modal;
1126         ot->poll = ED_operator_mask;
1127
1128         /* flags */
1129         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1130
1131         RNA_def_boolean(ot->srna, "slide_feather", 0, "Slide Feather", "First try to slide feather instead of vertex");
1132
1133         prop = RNA_def_boolean(ot->srna, "is_new_point", 0, "Slide New Point", "Newly created vertex is being slid");
1134         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1135 }
1136
1137 /******************** slide spline curvature *********************/
1138
1139 typedef struct SlideSplineCurvatureData {
1140         short event_invoke_type;
1141
1142         Mask *mask;
1143         MaskLayer *mask_layer;
1144         MaskSpline *spline;
1145         MaskSplinePoint *point;
1146         float u;
1147         bool accurate;
1148
1149         BezTriple *adjust_bezt, *other_bezt;
1150         BezTriple bezt_backup, other_bezt_backup;
1151
1152         float prev_mouse_coord[2];
1153         float prev_spline_coord[2];
1154
1155         float P0[2], P1[2], P2[2], P3[3];
1156 } SlideSplineCurvatureData;
1157
1158 static void cancel_slide_spline_curvature(SlideSplineCurvatureData *slide_data)
1159 {
1160         *slide_data->adjust_bezt = slide_data->bezt_backup;
1161         *slide_data->other_bezt = slide_data->other_bezt_backup;
1162 }
1163
1164
1165 static void free_slide_spline_curvature_data(SlideSplineCurvatureData *slide_data)
1166 {
1167         MEM_freeN(slide_data);
1168 }
1169
1170 static bool slide_spline_curvature_check(bContext *C, const wmEvent *event)
1171 {
1172         Mask *mask = CTX_data_edit_mask(C);
1173         float co[2];
1174         const float threshold = 19.0f;
1175
1176         ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, co);
1177
1178         if (ED_mask_point_find_nearest(C, mask, co, threshold, NULL, NULL, NULL, NULL)) {
1179                 return false;
1180         }
1181
1182         if (ED_mask_feather_find_nearest(C, mask, co, threshold, NULL, NULL, NULL, NULL, NULL)) {
1183                 return false;
1184         }
1185
1186         return true;
1187 }
1188
1189 static SlideSplineCurvatureData *slide_spline_curvature_customdata(
1190         bContext *C, const wmEvent *event)
1191 {
1192         const float threshold = 19.0f;
1193
1194         Mask *mask = CTX_data_edit_mask(C);
1195         SlideSplineCurvatureData *slide_data;
1196         MaskLayer *mask_layer;
1197         MaskSpline *spline;
1198         MaskSplinePoint *point;
1199         float u, co[2];
1200         BezTriple *next_bezt;
1201
1202         ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, co);
1203
1204         if (!ED_mask_find_nearest_diff_point(C, mask, co, threshold, false,
1205                                              NULL, true, false,
1206                                              &mask_layer, &spline, &point, &u,
1207                                              NULL))
1208         {
1209                 return NULL;
1210         }
1211
1212         next_bezt = BKE_mask_spline_point_next_bezt(spline, spline->points, point);
1213         if (next_bezt == NULL) {
1214                 return NULL;
1215         }
1216
1217         slide_data = MEM_callocN(sizeof(SlideSplineCurvatureData), "slide curvature slide");
1218         slide_data->event_invoke_type = event->type;
1219         slide_data->mask = mask;
1220         slide_data->mask_layer = mask_layer;
1221         slide_data->spline = spline;
1222         slide_data->point = point;
1223         slide_data->u = u;
1224
1225         copy_v2_v2(slide_data->prev_mouse_coord, co);
1226         BKE_mask_point_segment_co(spline, point, u, slide_data->prev_spline_coord);
1227
1228         copy_v2_v2(slide_data->P0, point->bezt.vec[1]);
1229         copy_v2_v2(slide_data->P1, point->bezt.vec[2]);
1230         copy_v2_v2(slide_data->P2, next_bezt->vec[0]);
1231         copy_v2_v2(slide_data->P3, next_bezt->vec[1]);
1232
1233         /* Depending to which end we're closer to adjust either left or right side of the spline. */
1234         if (u <= 0.5f) {
1235                 slide_data->adjust_bezt = &point->bezt;
1236                 slide_data->other_bezt = next_bezt;
1237         }
1238         else {
1239                 slide_data->adjust_bezt = next_bezt;
1240                 slide_data->other_bezt = &point->bezt;
1241         }
1242
1243         /* Data needed for restoring state. */
1244         slide_data->bezt_backup = *slide_data->adjust_bezt;
1245         slide_data->other_bezt_backup = *slide_data->other_bezt;
1246
1247         /* Let's dont touch other side of the point for now, so set handle to FREE. */
1248         if (u < 0.5f) {
1249                 if (slide_data->adjust_bezt->h2 <= HD_VECT) {
1250                         slide_data->adjust_bezt->h2 = HD_FREE;
1251                 }
1252         }
1253         else {
1254                 if (slide_data->adjust_bezt->h1 <= HD_VECT) {
1255                         slide_data->adjust_bezt->h1 = HD_FREE;
1256                 }
1257         }
1258
1259         /* Change selection */
1260         ED_mask_select_toggle_all(mask, SEL_DESELECT);
1261         slide_data->adjust_bezt->f2 |= SELECT;
1262         slide_data->other_bezt->f2 |= SELECT;
1263         if (u < 0.5f) {
1264                 slide_data->adjust_bezt->f3 |= SELECT;
1265                 slide_data->other_bezt->f1 |= SELECT;
1266         }
1267         else {
1268                 slide_data->adjust_bezt->f1 |= SELECT;
1269                 slide_data->other_bezt->f3 |= SELECT;
1270         }
1271         mask_layer->act_spline = spline;
1272         mask_layer->act_point = point;
1273         ED_mask_select_flush_all(mask);
1274
1275         return slide_data;
1276 }
1277
1278 static int slide_spline_curvature_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1279 {
1280         Mask *mask = CTX_data_edit_mask(C);
1281         SlideSplineCurvatureData *slide_data;
1282
1283         if (mask == NULL) {
1284                 return OPERATOR_PASS_THROUGH;
1285         }
1286
1287         /* Be sure we don't conflict with point slide here. */
1288         if (!slide_spline_curvature_check(C, event)) {
1289                 return OPERATOR_PASS_THROUGH;
1290         }
1291
1292         slide_data = slide_spline_curvature_customdata(C, event);
1293         if (slide_data != NULL) {
1294                 op->customdata = slide_data;
1295                 WM_event_add_modal_handler(C, op);
1296                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
1297                 return OPERATOR_RUNNING_MODAL;
1298         }
1299
1300         return OPERATOR_PASS_THROUGH;
1301 }
1302
1303 static void slide_spline_solve_P1(const float u,
1304                                   const float B[2],
1305                                   const float P0[2],
1306                                   const float P2[2],
1307                                   const float P3[2],
1308                                   float solution[2])
1309 {
1310         const float u2 = u * u, u3 = u * u * u;
1311         const float v = 1.0f - u;
1312         const float v2 = v * v, v3 = v * v * v;
1313         const float inv_divider = 1.0f / (3.0f * v2 * u);
1314         const float t = 3.0f * v * u2;
1315         solution[0] = -(v3 * P0[0] + t * P2[0] + u3 * P3[0] - B[0]) * inv_divider;
1316         solution[1] = -(v3 * P0[1] + t * P2[1] + u3 * P3[1] - B[1]) * inv_divider;
1317 }
1318
1319 static void slide_spline_solve_P2(const float u,
1320                                   const float B[2],
1321                                   const float P0[2],
1322                                   const float P1[2],
1323                                   const float P3[2],
1324                                   float solution[2])
1325 {
1326         const float u2 = u * u, u3 = u * u * u;
1327         const float v = 1.0f - u;
1328         const float v2 = v * v, v3 = v * v * v;
1329         const float inv_divider = 1.0f / (3.0f * v * u2);
1330         const float t = 3.0f * v2 * u;
1331         solution[0] = -(v3 * P0[0] + t * P1[0] + u3 * P3[0] - B[0]) * inv_divider;
1332         solution[1] = -(v3 * P0[1] + t * P1[1] + u3 * P3[1] - B[1]) * inv_divider;
1333 }
1334
1335 static int slide_spline_curvature_modal(bContext *C, wmOperator *op, const wmEvent *event)
1336 {
1337         Scene *scene = CTX_data_scene(C);
1338         const float margin = 0.2f;
1339         SlideSplineCurvatureData *slide_data = (SlideSplineCurvatureData *) op->customdata;
1340         float u = slide_data->u;
1341
1342         switch (event->type) {
1343                 case LEFTSHIFTKEY:
1344                 case RIGHTSHIFTKEY:
1345                 case LEFTCTRLKEY:
1346                 case RIGHTCTRLKEY:
1347                         if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY)) {
1348                                 slide_data->accurate = (event->val == KM_PRESS);
1349                         }
1350
1351                         if (ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY)) {
1352                                 if (event->val == KM_PRESS) {
1353                                         slide_data->adjust_bezt->h1 = slide_data->adjust_bezt->h2 = HD_FREE;
1354                                         if ((u > margin && u < 0.5f) || (u >= 0.5f && u < 1.0f - margin)) {
1355                                                 slide_data->other_bezt->h1 = slide_data->other_bezt->h2 = HD_FREE;
1356                                         }
1357                                 }
1358                                 else if (event->val == KM_RELEASE) {
1359                                         slide_data->adjust_bezt->h1 = slide_data->bezt_backup.h1;
1360                                         slide_data->adjust_bezt->h2 = slide_data->bezt_backup.h2;
1361                                         slide_data->other_bezt->h1 = slide_data->other_bezt_backup.h1;
1362                                         slide_data->other_bezt->h2 = slide_data->other_bezt_backup.h2;
1363                                 }
1364
1365                                 if (u < 0.5f) {
1366                                         copy_v2_v2(slide_data->adjust_bezt->vec[0], slide_data->bezt_backup.vec[0]);
1367                                         copy_v2_v2(slide_data->other_bezt->vec[2], slide_data->other_bezt_backup.vec[2]);
1368                                 }
1369                                 else {
1370                                         copy_v2_v2(slide_data->adjust_bezt->vec[2], slide_data->bezt_backup.vec[2]);
1371                                         copy_v2_v2(slide_data->other_bezt->vec[0], slide_data->other_bezt_backup.vec[0]);
1372                                 }
1373
1374                         }
1375
1376                         ATTR_FALLTHROUGH;  /* update CV position */
1377                 case MOUSEMOVE:
1378                 {
1379                         float B[2], mouse_coord[2], delta[2];
1380
1381                         /* Get coordinate spline is expected to go through. */
1382                         ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, mouse_coord);
1383                         sub_v2_v2v2(delta, mouse_coord, slide_data->prev_mouse_coord);
1384                         if (slide_data->accurate) {
1385                                 mul_v2_fl(delta, 0.2f);
1386                         }
1387                         add_v2_v2v2(B, slide_data->prev_spline_coord, delta);
1388                         copy_v2_v2(slide_data->prev_spline_coord, B);
1389                         copy_v2_v2(slide_data->prev_mouse_coord, mouse_coord);
1390
1391                         if (u < 0.5f) {
1392                                 float oldP2[2];
1393                                 bool need_restore_P2 = false;
1394
1395                                 if (u > margin) {
1396                                         float solution[2];
1397                                         float x = (u - margin) * 0.5f / (0.5f - margin);
1398                                         float weight =  (3 * x * x - 2 * x * x * x);
1399
1400                                         slide_spline_solve_P2(u, B,
1401                                                               slide_data->P0,
1402                                                               slide_data->P1,
1403                                                               slide_data->P3,
1404                                                               solution);
1405
1406                                         copy_v2_v2(oldP2, slide_data->P2);
1407                                         interp_v2_v2v2(slide_data->P2, slide_data->P2, solution, weight);
1408                                         copy_v2_v2(slide_data->other_bezt->vec[0], slide_data->P2);
1409                                         need_restore_P2 = true;
1410
1411                                         /* Tweak handle type in order to be able to apply the delta. */
1412                                         if (weight > 0.0f) {
1413                                                 if (slide_data->other_bezt->h1 <= HD_VECT) {
1414                                                         slide_data->other_bezt->h1 = HD_FREE;
1415                                                 }
1416                                         }
1417                                 }
1418
1419                                 slide_spline_solve_P1(u, B,
1420                                                       slide_data->P0,
1421                                                       slide_data->P2,
1422                                                       slide_data->P3,
1423                                                       slide_data->adjust_bezt->vec[2]);
1424
1425                                 if (need_restore_P2) {
1426                                         copy_v2_v2(slide_data->P2, oldP2);
1427                                 }
1428                         }
1429                         else {
1430                                 float oldP1[2];
1431                                 bool need_restore_P1 = false;
1432
1433                                 if (u < 1.0f - margin) {
1434                                         float solution[2];
1435                                         float x = ((1.0f - u) - margin) * 0.5f / (0.5f - margin);
1436                                         float weight = 3 * x * x - 2 * x * x * x;
1437
1438                                         slide_spline_solve_P1(u, B,
1439                                                               slide_data->P0,
1440                                                               slide_data->P2,
1441                                                               slide_data->P3,
1442                                                               solution);
1443
1444                                         copy_v2_v2(oldP1, slide_data->P1);
1445                                         interp_v2_v2v2(slide_data->P1, slide_data->P1, solution, weight);
1446                                         copy_v2_v2(slide_data->other_bezt->vec[2], slide_data->P1);
1447                                         need_restore_P1 = true;
1448
1449                                         /* Tweak handle type in order to be able to apply the delta. */
1450                                         if (weight > 0.0f) {
1451                                                 if (slide_data->other_bezt->h2 <= HD_VECT) {
1452                                                         slide_data->other_bezt->h2 = HD_FREE;
1453                                                 }
1454                                         }
1455                                 }
1456
1457                                 slide_spline_solve_P2(u, B,
1458                                                       slide_data->P0,
1459                                                       slide_data->P1,
1460                                                       slide_data->P3,
1461                                                       slide_data->adjust_bezt->vec[0]);
1462
1463                                 if (need_restore_P1) {
1464                                         copy_v2_v2(slide_data->P1, oldP1);
1465                                 }
1466                         }
1467
1468                         WM_event_add_notifier(C, NC_MASK | NA_EDITED, slide_data->mask);
1469                         DEG_id_tag_update(&slide_data->mask->id, 0);
1470
1471                         break;
1472                 }
1473
1474                 case LEFTMOUSE:
1475                 case RIGHTMOUSE:
1476                         if (event->type == slide_data->event_invoke_type && event->val == KM_RELEASE) {
1477                                 /* dont key sliding feather uw's */
1478                                 if (IS_AUTOKEY_ON(scene)) {
1479                                         ED_mask_layer_shape_auto_key(slide_data->mask_layer, CFRA);
1480                                 }
1481
1482                                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, slide_data->mask);
1483                                 DEG_id_tag_update(&slide_data->mask->id, 0);
1484
1485                                 free_slide_spline_curvature_data(slide_data); /* keep this last! */
1486                                 return OPERATOR_FINISHED;
1487                         }
1488
1489                         break;
1490
1491                 case ESCKEY:
1492                         cancel_slide_spline_curvature(slide_data);
1493
1494                         WM_event_add_notifier(C, NC_MASK | NA_EDITED, slide_data->mask);
1495                         DEG_id_tag_update(&slide_data->mask->id, 0);
1496
1497                         free_slide_spline_curvature_data(op->customdata); /* keep this last! */
1498                         return OPERATOR_CANCELLED;
1499         }
1500
1501         return OPERATOR_RUNNING_MODAL;
1502 }
1503
1504 void MASK_OT_slide_spline_curvature(wmOperatorType *ot)
1505 {
1506         /* identifiers */
1507         ot->name = "Slide Spline Curvature";
1508         ot->description = "Slide a point on the spline to define it's curvature";
1509         ot->idname = "MASK_OT_slide_spline_curvature";
1510
1511         /* api callbacks */
1512         ot->invoke = slide_spline_curvature_invoke;
1513         ot->modal = slide_spline_curvature_modal;
1514         ot->poll = ED_operator_mask;
1515
1516         /* flags */
1517         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1518 }
1519
1520 /******************** toggle cyclic *********************/
1521
1522 static int cyclic_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1523 {
1524         Mask *mask = CTX_data_edit_mask(C);
1525         MaskLayer *masklay;
1526
1527         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
1528                 MaskSpline *spline;
1529
1530                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
1531                         continue;
1532                 }
1533
1534                 for (spline = masklay->splines.first; spline; spline = spline->next) {
1535                         if (ED_mask_spline_select_check(spline)) {
1536                                 spline->flag ^= MASK_SPLINE_CYCLIC;
1537                         }
1538                 }
1539         }
1540
1541         DEG_id_tag_update(&mask->id, 0);
1542         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
1543
1544         return OPERATOR_FINISHED;
1545 }
1546
1547 void MASK_OT_cyclic_toggle(wmOperatorType *ot)
1548 {
1549         /* identifiers */
1550         ot->name = "Toggle Cyclic";
1551         ot->description = "Toggle cyclic for selected splines";
1552         ot->idname = "MASK_OT_cyclic_toggle";
1553
1554         /* api callbacks */
1555         ot->exec = cyclic_toggle_exec;
1556         ot->poll = ED_maskedit_mask_poll;
1557
1558         /* flags */
1559         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1560 }
1561
1562 /******************** delete *********************/
1563
1564 static void delete_feather_points(MaskSplinePoint *point)
1565 {
1566         int i, count = 0;
1567
1568         if (!point->tot_uw)
1569                 return;
1570
1571         for (i = 0; i < point->tot_uw; i++) {
1572                 if ((point->uw[i].flag & SELECT) == 0)
1573                         count++;
1574         }
1575
1576         if (count == 0) {
1577                 MEM_freeN(point->uw);
1578                 point->uw = NULL;
1579                 point->tot_uw = 0;
1580         }
1581         else {
1582                 MaskSplinePointUW *new_uw;
1583                 int j = 0;
1584
1585                 new_uw = MEM_callocN(count * sizeof(MaskSplinePointUW), "new mask uw points");
1586
1587                 for (i = 0; i < point->tot_uw; i++) {
1588                         if ((point->uw[i].flag & SELECT) == 0) {
1589                                 new_uw[j++] = point->uw[i];
1590                         }
1591                 }
1592
1593                 MEM_freeN(point->uw);
1594
1595                 point->uw = new_uw;
1596                 point->tot_uw = count;
1597         }
1598 }
1599
1600 static int delete_exec(bContext *C, wmOperator *UNUSED(op))
1601 {
1602         Scene *scene = CTX_data_scene(C);
1603         Mask *mask = CTX_data_edit_mask(C);
1604         MaskLayer *masklay;
1605         bool changed = false;
1606
1607         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
1608                 MaskSpline *spline;
1609                 int mask_layer_shape_ofs = 0;
1610
1611                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
1612                         continue;
1613                 }
1614
1615                 spline = masklay->splines.first;
1616
1617                 while (spline) {
1618                         const int tot_point_orig = spline->tot_point;
1619                         int i, count = 0;
1620                         MaskSpline *next_spline = spline->next;
1621
1622                         /* count unselected points */
1623                         for (i = 0; i < spline->tot_point; i++) {
1624                                 MaskSplinePoint *point = &spline->points[i];
1625
1626                                 if (!MASKPOINT_ISSEL_ANY(point))
1627                                         count++;
1628                         }
1629
1630                         if (count == 0) {
1631                                 /* delete the whole spline */
1632                                 BLI_remlink(&masklay->splines, spline);
1633                                 BKE_mask_spline_free(spline);
1634
1635                                 if (spline == masklay->act_spline) {
1636                                         masklay->act_spline = NULL;
1637                                         masklay->act_point = NULL;
1638                                 }
1639
1640                                 BKE_mask_layer_shape_changed_remove(masklay, mask_layer_shape_ofs, tot_point_orig);
1641                         }
1642                         else {
1643                                 MaskSplinePoint *new_points;
1644                                 int j;
1645
1646                                 new_points = MEM_callocN(count * sizeof(MaskSplinePoint), "deleteMaskPoints");
1647
1648                                 for (i = 0, j = 0; i < tot_point_orig; i++) {
1649                                         MaskSplinePoint *point = &spline->points[i];
1650
1651                                         if (!MASKPOINT_ISSEL_ANY(point)) {
1652                                                 if (point == masklay->act_point)
1653                                                         masklay->act_point = &new_points[j];
1654
1655                                                 delete_feather_points(point);
1656
1657                                                 new_points[j] = *point;
1658                                                 j++;
1659                                         }
1660                                         else {
1661                                                 if (point == masklay->act_point)
1662                                                         masklay->act_point = NULL;
1663
1664                                                 BKE_mask_point_free(point);
1665                                                 spline->tot_point--;
1666
1667                                                 BKE_mask_layer_shape_changed_remove(masklay, mask_layer_shape_ofs + j, 1);
1668                                         }
1669                                 }
1670
1671                                 mask_layer_shape_ofs += spline->tot_point;
1672
1673                                 MEM_freeN(spline->points);
1674                                 spline->points = new_points;
1675
1676                                 ED_mask_select_flush_all(mask);
1677                         }
1678
1679                         changed = true;
1680                         spline = next_spline;
1681                 }
1682
1683                 /* not essential but confuses users when there are keys with no data!
1684                  * assume if they delete all data from the layer they also dont care about keys */
1685                 if (BLI_listbase_is_empty(&masklay->splines)) {
1686                         BKE_mask_layer_free_shapes(masklay);
1687                 }
1688         }
1689
1690         if (!changed) {
1691                 return OPERATOR_CANCELLED;
1692         }
1693
1694         /* TODO: only update edited splines */
1695         BKE_mask_update_display(mask, CFRA);
1696
1697         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
1698
1699         return OPERATOR_FINISHED;
1700 }
1701
1702 void MASK_OT_delete(wmOperatorType *ot)
1703 {
1704         /* identifiers */
1705         ot->name = "Delete";
1706         ot->description = "Delete selected control points or splines";
1707         ot->idname = "MASK_OT_delete";
1708
1709         /* api callbacks */
1710         ot->invoke = WM_operator_confirm;
1711         ot->exec = delete_exec;
1712         ot->poll = ED_maskedit_mask_poll;
1713
1714         /* flags */
1715         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1716 }
1717
1718 /* *** switch direction *** */
1719 static int mask_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
1720 {
1721         Scene *scene = CTX_data_scene(C);
1722         Mask *mask = CTX_data_edit_mask(C);
1723         MaskLayer *masklay;
1724
1725         bool changed = false;
1726
1727         /* do actual selection */
1728         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
1729                 MaskSpline *spline;
1730                 bool changed_layer = false;
1731
1732                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
1733                         continue;
1734                 }
1735
1736                 for (spline = masklay->splines.first; spline; spline = spline->next) {
1737                         if (ED_mask_spline_select_check(spline)) {
1738                                 BKE_mask_spline_direction_switch(masklay, spline);
1739                                 changed = true;
1740                                 changed_layer = true;
1741                         }
1742                 }
1743
1744                 if (changed_layer) {
1745                         if (IS_AUTOKEY_ON(scene)) {
1746                                 ED_mask_layer_shape_auto_key(masklay, CFRA);
1747                         }
1748                 }
1749         }
1750
1751         if (changed) {
1752                 /* TODO: only update this spline */
1753                 BKE_mask_update_display(mask, CFRA);
1754
1755                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
1756                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
1757
1758                 return OPERATOR_FINISHED;
1759         }
1760
1761         return OPERATOR_CANCELLED;
1762 }
1763
1764 void MASK_OT_switch_direction(wmOperatorType *ot)
1765 {
1766         /* identifiers */
1767         ot->name = "Switch Direction";
1768         ot->description = "Switch direction of selected splines";
1769         ot->idname = "MASK_OT_switch_direction";
1770
1771         /* api callbacks */
1772         ot->exec = mask_switch_direction_exec;
1773         ot->poll = ED_maskedit_mask_poll;
1774
1775         /* flags */
1776         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1777 }
1778
1779
1780 /* *** recalc normals *** */
1781 static int mask_normals_make_consistent_exec(bContext *C, wmOperator *UNUSED(op))
1782 {
1783         Scene *scene = CTX_data_scene(C);
1784         Mask *mask = CTX_data_edit_mask(C);
1785         MaskLayer *masklay;
1786         int i;
1787
1788         bool changed = false;
1789
1790         /* do actual selection */
1791         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
1792                 MaskSpline *spline;
1793                 bool changed_layer = false;
1794
1795                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
1796                         continue;
1797                 }
1798
1799                 for (spline = masklay->splines.first; spline; spline = spline->next) {
1800                         for (i = 0; i < spline->tot_point; i++) {
1801                                 MaskSplinePoint *point = &spline->points[i];
1802
1803                                 if (MASKPOINT_ISSEL_ANY(point)) {
1804                                         BKE_mask_calc_handle_point_auto(spline, point, false);
1805                                         changed = true;
1806                                         changed_layer = true;
1807                                 }
1808                         }
1809                 }
1810
1811                 if (changed_layer) {
1812                         if (IS_AUTOKEY_ON(scene)) {
1813                                 ED_mask_layer_shape_auto_key(masklay, CFRA);
1814                         }
1815                 }
1816         }
1817
1818         if (changed) {
1819                 /* TODO: only update this spline */
1820                 BKE_mask_update_display(mask, CFRA);
1821
1822                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
1823                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
1824
1825                 return OPERATOR_FINISHED;
1826         }
1827
1828         return OPERATOR_CANCELLED;
1829 }
1830
1831 /* named to match mesh recalc normals */
1832 void MASK_OT_normals_make_consistent(wmOperatorType *ot)
1833 {
1834         /* identifiers */
1835         ot->name = "Recalc Normals";
1836         ot->description = "Re-calculate the direction of selected handles";
1837         ot->idname = "MASK_OT_normals_make_consistent";
1838
1839         /* api callbacks */
1840         ot->exec = mask_normals_make_consistent_exec;
1841         ot->poll = ED_maskedit_mask_poll;
1842
1843         /* flags */
1844         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1845 }
1846
1847
1848 /******************** set handle type *********************/
1849
1850 static int set_handle_type_exec(bContext *C, wmOperator *op)
1851 {
1852         Mask *mask = CTX_data_edit_mask(C);
1853         MaskLayer *masklay;
1854         int handle_type = RNA_enum_get(op->ptr, "type");
1855
1856         bool changed = false;
1857
1858         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
1859                 MaskSpline *spline;
1860                 int i;
1861
1862                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
1863                         continue;
1864                 }
1865
1866                 for (spline = masklay->splines.first; spline; spline = spline->next) {
1867                         for (i = 0; i < spline->tot_point; i++) {
1868                                 MaskSplinePoint *point = &spline->points[i];
1869
1870                                 if (MASKPOINT_ISSEL_ANY(point)) {
1871                                         BezTriple *bezt = &point->bezt;
1872
1873                                         if (bezt->f2 & SELECT) {
1874                                                 bezt->h1 = handle_type;
1875                                                 bezt->h2 = handle_type;
1876                                         }
1877                                         else {
1878                                                 if (bezt->f1 & SELECT) {
1879                                                         bezt->h1 = handle_type;
1880                                                 }
1881                                                 if (bezt->f3 & SELECT) {
1882                                                         bezt->h2 = handle_type;
1883                                                 }
1884                                         }
1885
1886                                         if (handle_type == HD_ALIGN) {
1887                                                 float vec[3];
1888                                                 sub_v3_v3v3(vec, bezt->vec[0], bezt->vec[1]);
1889                                                 add_v3_v3v3(bezt->vec[2], bezt->vec[1], vec);
1890                                         }
1891
1892                                         changed = true;
1893                                 }
1894                         }
1895                 }
1896         }
1897
1898         if (changed) {
1899                 WM_event_add_notifier(C, NC_MASK | ND_DATA, mask);
1900                 DEG_id_tag_update(&mask->id, 0);
1901
1902                 return OPERATOR_FINISHED;
1903         }
1904         return OPERATOR_CANCELLED;
1905 }
1906
1907 void MASK_OT_handle_type_set(wmOperatorType *ot)
1908 {
1909         static const EnumPropertyItem editcurve_handle_type_items[] = {
1910                 {HD_AUTO, "AUTO", 0, "Auto", ""},
1911                 {HD_VECT, "VECTOR", 0, "Vector", ""},
1912                 {HD_ALIGN, "ALIGNED", 0, "Aligned Single", ""},
1913                 {HD_ALIGN_DOUBLESIDE, "ALIGNED_DOUBLESIDE", 0, "Aligned", ""},
1914                 {HD_FREE, "FREE", 0, "Free", ""},
1915                 {0, NULL, 0, NULL, NULL},
1916         };
1917
1918         /* identifiers */
1919         ot->name = "Set Handle Type";
1920         ot->description = "Set type of handles for selected control points";
1921         ot->idname = "MASK_OT_handle_type_set";
1922
1923         /* api callbacks */
1924         ot->invoke = WM_menu_invoke;
1925         ot->exec = set_handle_type_exec;
1926         ot->poll = ED_maskedit_mask_poll;
1927
1928         /* flags */
1929         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1930
1931         /* properties */
1932         ot->prop = RNA_def_enum(ot->srna, "type", editcurve_handle_type_items, 1, "Type", "Spline type");
1933 }
1934
1935
1936 /* ********* clear/set restrict view *********/
1937 static int mask_hide_view_clear_exec(bContext *C, wmOperator *op)
1938 {
1939         Mask *mask = CTX_data_edit_mask(C);
1940         MaskLayer *masklay;
1941         bool changed = false;
1942         const bool select = RNA_boolean_get(op->ptr, "select");
1943
1944         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
1945
1946                 if (masklay->restrictflag & OB_RESTRICT_VIEW) {
1947                         ED_mask_layer_select_set(masklay, select);
1948                         masklay->restrictflag &= ~OB_RESTRICT_VIEW;
1949                         changed = true;
1950                 }
1951         }
1952
1953         if (changed) {
1954                 WM_event_add_notifier(C, NC_MASK | ND_DRAW, mask);
1955                 DEG_id_tag_update(&mask->id, 0);
1956
1957                 return OPERATOR_FINISHED;
1958         }
1959         else {
1960                 return OPERATOR_CANCELLED;
1961         }
1962 }
1963
1964 void MASK_OT_hide_view_clear(wmOperatorType *ot)
1965 {
1966
1967         /* identifiers */
1968         ot->name = "Clear Restrict View";
1969         ot->description = "Reveal the layer by setting the hide flag";
1970         ot->idname = "MASK_OT_hide_view_clear";
1971
1972         /* api callbacks */
1973         ot->exec = mask_hide_view_clear_exec;
1974         ot->poll = ED_maskedit_mask_poll;
1975
1976         /* flags */
1977         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1978
1979         RNA_def_boolean(ot->srna, "select", true, "Select", "");
1980 }
1981
1982 static int mask_hide_view_set_exec(bContext *C, wmOperator *op)
1983 {
1984         Mask *mask = CTX_data_edit_mask(C);
1985         MaskLayer *masklay;
1986         const bool unselected = RNA_boolean_get(op->ptr, "unselected");
1987         bool changed = false;
1988
1989         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
1990
1991                 if (masklay->restrictflag & MASK_RESTRICT_SELECT) {
1992                         continue;
1993                 }
1994
1995                 if (!unselected) {
1996                         if (ED_mask_layer_select_check(masklay)) {
1997                                 ED_mask_layer_select_set(masklay, false);
1998
1999                                 masklay->restrictflag |= OB_RESTRICT_VIEW;
2000                                 changed = true;
2001                                 if (masklay == BKE_mask_layer_active(mask)) {
2002                                         BKE_mask_layer_active_set(mask, NULL);
2003                                 }
2004                         }
2005                 }
2006                 else {
2007                         if (!ED_mask_layer_select_check(masklay)) {
2008                                 masklay->restrictflag |= OB_RESTRICT_VIEW;
2009                                 changed = true;
2010                                 if (masklay == BKE_mask_layer_active(mask)) {
2011                                         BKE_mask_layer_active_set(mask, NULL);
2012                                 }
2013                         }
2014                 }
2015         }
2016
2017         if (changed) {
2018                 WM_event_add_notifier(C, NC_MASK | ND_DRAW, mask);
2019                 DEG_id_tag_update(&mask->id, 0);
2020
2021                 return OPERATOR_FINISHED;
2022         }
2023         else {
2024                 return OPERATOR_CANCELLED;
2025         }
2026 }
2027
2028 void MASK_OT_hide_view_set(wmOperatorType *ot)
2029 {
2030         /* identifiers */
2031         ot->name = "Set Restrict View";
2032         ot->description = "Hide the layer by setting the hide flag";
2033         ot->idname = "MASK_OT_hide_view_set";
2034
2035         /* api callbacks */
2036         ot->exec = mask_hide_view_set_exec;
2037         ot->poll = ED_maskedit_mask_poll;
2038
2039         /* flags */
2040         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2041
2042         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected layers");
2043 }
2044
2045
2046 static int mask_feather_weight_clear_exec(bContext *C, wmOperator *UNUSED(op))
2047 {
2048         Scene *scene = CTX_data_scene(C);
2049         Mask *mask = CTX_data_edit_mask(C);
2050         MaskLayer *masklay;
2051         bool changed = false;
2052         int i;
2053
2054         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
2055                 MaskSpline *spline;
2056
2057                 if (masklay->restrictflag & (MASK_RESTRICT_SELECT | MASK_RESTRICT_VIEW)) {
2058                         continue;
2059                 }
2060
2061                 for (spline = masklay->splines.first; spline; spline = spline->next) {
2062                         for (i = 0; i < spline->tot_point; i++) {
2063                                 MaskSplinePoint *point = &spline->points[i];
2064
2065                                 if (MASKPOINT_ISSEL_ANY(point)) {
2066                                         BezTriple *bezt = &point->bezt;
2067                                         bezt->weight = 0.0f;
2068                                         changed = true;
2069                                 }
2070                         }
2071                 }
2072         }
2073
2074         if (changed) {
2075                 /* TODO: only update edited splines */
2076                 BKE_mask_update_display(mask, CFRA);
2077
2078                 WM_event_add_notifier(C, NC_MASK | ND_DRAW, mask);
2079                 DEG_id_tag_update(&mask->id, 0);
2080
2081                 return OPERATOR_FINISHED;
2082         }
2083         else {
2084                 return OPERATOR_CANCELLED;
2085         }
2086 }
2087
2088 void MASK_OT_feather_weight_clear(wmOperatorType *ot)
2089 {
2090         /* identifiers */
2091         ot->name = "Clear Feather Weight";
2092         ot->description = "Reset the feather weight to zero";
2093         ot->idname = "MASK_OT_feather_weight_clear";
2094
2095         /* api callbacks */
2096         ot->exec = mask_feather_weight_clear_exec;
2097         ot->poll = ED_maskedit_mask_poll;
2098
2099         /* flags */
2100         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2101 }
2102
2103 /******************** move mask layer operator *********************/
2104
2105 static bool mask_layer_move_poll(bContext *C)
2106 {
2107         if (ED_maskedit_mask_poll(C)) {
2108                 Mask *mask = CTX_data_edit_mask(C);
2109
2110                 return mask->masklay_tot > 0;
2111         }
2112
2113         return false;
2114 }
2115
2116 static int mask_layer_move_exec(bContext *C, wmOperator *op)
2117 {
2118         Mask *mask = CTX_data_edit_mask(C);
2119         MaskLayer *mask_layer = BLI_findlink(&mask->masklayers, mask->masklay_act);
2120         MaskLayer *mask_layer_other;
2121         int direction = RNA_enum_get(op->ptr, "direction");
2122
2123         if (!mask_layer)
2124                 return OPERATOR_CANCELLED;
2125
2126         if (direction == -1) {
2127                 mask_layer_other = mask_layer->prev;
2128
2129                 if (!mask_layer_other)
2130                         return OPERATOR_CANCELLED;
2131
2132                 BLI_remlink(&mask->masklayers, mask_layer);
2133                 BLI_insertlinkbefore(&mask->masklayers, mask_layer_other, mask_layer);
2134                 mask->masklay_act--;
2135         }
2136         else if (direction == 1) {
2137                 mask_layer_other = mask_layer->next;
2138
2139                 if (!mask_layer_other)
2140                         return OPERATOR_CANCELLED;
2141
2142                 BLI_remlink(&mask->masklayers, mask_layer);
2143                 BLI_insertlinkafter(&mask->masklayers, mask_layer_other, mask_layer);
2144                 mask->masklay_act++;
2145         }
2146
2147         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
2148
2149         return OPERATOR_FINISHED;
2150 }
2151
2152 void MASK_OT_layer_move(wmOperatorType *ot)
2153 {
2154         static const EnumPropertyItem direction_items[] = {
2155                 {-1, "UP", 0, "Up", ""},
2156                 {1, "DOWN", 0, "Down", ""},
2157                 {0, NULL, 0, NULL, NULL},
2158         };
2159
2160         /* identifiers */
2161         ot->name = "Move Layer";
2162         ot->description = "Move the active layer up/down in the list";
2163         ot->idname = "MASK_OT_layer_move";
2164
2165         /* api callbacks */
2166         ot->exec = mask_layer_move_exec;
2167         ot->poll = mask_layer_move_poll;
2168
2169         /* flags */
2170         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2171
2172         /* properties */
2173         RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move the active layer");
2174 }
2175
2176 /******************** duplicate *********************/
2177
2178 static int mask_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
2179 {
2180         Scene *scene = CTX_data_scene(C);
2181         Mask *mask = CTX_data_edit_mask(C);
2182         MaskLayer *mask_layer;
2183
2184         for (mask_layer = mask->masklayers.first;
2185              mask_layer;
2186              mask_layer = mask_layer->next)
2187         {
2188                 MaskSpline *spline;
2189
2190                 for (spline = mask_layer->splines.last;
2191                      spline;
2192                      spline = spline->prev)
2193                 {
2194                         MaskSplinePoint *point = spline->points;
2195                         int i = 0;
2196                         while (i < spline->tot_point) {
2197                                 int start = i, end = -1;
2198                                 /* Find next selected segment. */
2199                                 while (MASKPOINT_ISSEL_ANY(point)) {
2200                                         BKE_mask_point_select_set(point, false);
2201                                         end = i;
2202                                         if (i >= spline->tot_point - 1) {
2203                                                 break;
2204                                         }
2205                                         i++;
2206                                         point++;
2207                                 }
2208                                 if (end >= start) {
2209                                         int tot_point;
2210                                         int tot_point_shape_start = 0;
2211                                         MaskSpline *new_spline = BKE_mask_spline_add(mask_layer);
2212                                         MaskSplinePoint *new_point;
2213                                         int b;
2214
2215                                         /* BKE_mask_spline_add might allocate the points,
2216                                          * need to free them in this case. */
2217                                         if (new_spline->points) {
2218                                                 MEM_freeN(new_spline->points);
2219                                         }
2220
2221                                         /* Copy options from old spline. */
2222                                         new_spline->flag = spline->flag;
2223                                         new_spline->offset_mode = spline->offset_mode;
2224                                         new_spline->weight_interp = spline->weight_interp;
2225                                         new_spline->parent = spline->parent;
2226
2227                                         /* Allocate new points and copy them from old spline. */
2228                                         new_spline->tot_point = end - start + 1;
2229                                         new_spline->points = MEM_mallocN(sizeof(MaskSplinePoint) * new_spline->tot_point,
2230                                                                          "duplicated mask points");
2231
2232                                         memcpy(new_spline->points, spline->points + start,
2233                                                new_spline->tot_point * sizeof(MaskSplinePoint));
2234
2235                                         tot_point = new_spline->tot_point;
2236
2237                                         /* animation requires points added one by one */
2238                                         if (mask_layer->splines_shapes.first) {
2239                                                 new_spline->tot_point = 0;
2240                                                 tot_point_shape_start = BKE_mask_layer_shape_spline_to_index(mask_layer, new_spline);
2241                                         }
2242
2243                                         /* Select points and duplicate their UWs (if needed). */
2244                                         for (b = 0, new_point = new_spline->points;
2245                                              b < tot_point;
2246                                              b++, new_point++)
2247                                         {
2248                                                 if (new_point->uw) {
2249                                                         new_point->uw = MEM_dupallocN(new_point->uw);
2250                                                 }
2251                                                 BKE_mask_point_select_set(new_point, true);
2252
2253
2254                                                 if (mask_layer->splines_shapes.first) {
2255                                                         new_spline->tot_point++;
2256                                                         BKE_mask_layer_shape_changed_add(mask_layer, tot_point_shape_start + b, true, false);
2257                                                 }
2258                                         }
2259
2260                                         /* Clear cyclic flag if we didn't copy the whole spline. */
2261                                         if (new_spline->flag & MASK_SPLINE_CYCLIC) {
2262                                                 if (start != 0 || end != spline->tot_point - 1) {
2263                                                         new_spline->flag &= ~MASK_SPLINE_CYCLIC;
2264                                                 }
2265                                         }
2266
2267                                         /* Flush selection to splines. */
2268                                         new_spline->flag |= SELECT;
2269                                         spline->flag &= ~SELECT;
2270
2271                                         mask_layer->act_spline = new_spline;
2272                                 }
2273                                 i++;
2274                                 point++;
2275                         }
2276                 }
2277         }
2278
2279         /* TODO: only update edited splines */
2280         BKE_mask_update_display(mask, CFRA);
2281
2282         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
2283
2284         return OPERATOR_FINISHED;
2285 }
2286
2287 void MASK_OT_duplicate(wmOperatorType *ot)
2288 {
2289         /* identifiers */
2290         ot->name = "Duplicate Mask";
2291         ot->description = "Duplicate selected control points and segments between them";
2292         ot->idname = "MASK_OT_duplicate";
2293
2294         /* api callbacks */
2295         ot->exec = mask_duplicate_exec;
2296         ot->poll = ED_maskedit_mask_poll;
2297
2298         /* flags */
2299         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2300 }
2301
2302 /********************** copy splines to clipboard operator *********************/
2303
2304 static int copy_splines_exec(bContext *C, wmOperator *UNUSED(op))
2305 {
2306         Mask *mask = CTX_data_edit_mask(C);
2307         MaskLayer *mask_layer = BKE_mask_layer_active(mask);
2308
2309         if (mask_layer == NULL) {
2310                 return OPERATOR_CANCELLED;
2311         }
2312
2313         BKE_mask_clipboard_copy_from_layer(mask_layer);
2314
2315         return OPERATOR_FINISHED;
2316 }
2317
2318 void MASK_OT_copy_splines(wmOperatorType *ot)
2319 {
2320         /* identifiers */
2321         ot->name = "Copy Splines";
2322         ot->description = "Copy selected splines to clipboard";
2323         ot->idname = "MASK_OT_copy_splines";
2324
2325         /* api callbacks */
2326         ot->exec = copy_splines_exec;
2327         ot->poll = ED_maskedit_mask_poll;
2328
2329         /* flags */
2330         ot->flag = OPTYPE_REGISTER;
2331 }
2332
2333 /********************** paste tracks from clipboard operator *********************/
2334
2335 static bool paste_splines_poll(bContext *C)
2336 {
2337         if (ED_maskedit_mask_poll(C)) {
2338                 return BKE_mask_clipboard_is_empty() == false;
2339         }
2340
2341         return 0;
2342 }
2343
2344 static int paste_splines_exec(bContext *C, wmOperator *UNUSED(op))
2345 {
2346         Scene *scene = CTX_data_scene(C);
2347         Mask *mask = CTX_data_edit_mask(C);
2348         MaskLayer *mask_layer = BKE_mask_layer_active(mask);
2349
2350         if (mask_layer == NULL) {
2351                 mask_layer = BKE_mask_layer_new(mask, "");
2352         }
2353
2354         BKE_mask_clipboard_paste_to_layer(CTX_data_main(C), mask_layer);
2355
2356         /* TODO: only update edited splines */
2357         BKE_mask_update_display(mask, CFRA);
2358
2359         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
2360
2361         return OPERATOR_FINISHED;
2362 }
2363
2364 void MASK_OT_paste_splines(wmOperatorType *ot)
2365 {
2366         /* identifiers */
2367         ot->name = "Paste Splines";
2368         ot->description = "Paste splines from clipboard";
2369         ot->idname = "MASK_OT_paste_splines";
2370
2371         /* api callbacks */
2372         ot->exec = paste_splines_exec;
2373         ot->poll = paste_splines_poll;
2374
2375         /* flags */
2376         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2377 }