use the zoom level to set the size for new mask point handle sizes (artist request...
[blender.git] / source / blender / editors / mask / mask_add.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2012 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation,
23  *                 Sergey Sharybin
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/mask/mask_add.c
29  *  \ingroup edmask
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_math.h"
35
36 #include "BKE_context.h"
37 #include "BKE_depsgraph.h"
38 #include "BKE_mask.h"
39
40 #include "DNA_scene_types.h"
41 #include "DNA_screen_types.h"
42 #include "DNA_mask_types.h"
43 #include "DNA_object_types.h"  /* SELECT */
44
45 #include "WM_api.h"
46 #include "WM_types.h"
47
48 #include "ED_mask.h"  /* own include */
49
50 #include "RNA_access.h"
51 #include "RNA_define.h"
52
53 #include "mask_intern.h"  /* own include */
54
55
56 static int find_nearest_diff_point(const bContext *C, Mask *mask, const float normal_co[2], int threshold, int feather,
57                                    MaskLayer **masklay_r, MaskSpline **spline_r, MaskSplinePoint **point_r,
58                                    float *u_r, float tangent[2],
59                                    const short use_deform)
60 {
61         ScrArea *sa = CTX_wm_area(C);
62         ARegion *ar = CTX_wm_region(C);
63
64         MaskLayer *masklay, *point_masklay;
65         MaskSpline *point_spline;
66         MaskSplinePoint *point = NULL;
67         float dist, co[2];
68         int width, height;
69         float u;
70         float scalex, scaley;
71
72         ED_mask_get_size(sa, &width, &height);
73         ED_mask_pixelspace_factor(sa, ar, &scalex, &scaley);
74
75         co[0] = normal_co[0] * scalex;
76         co[1] = normal_co[1] * scaley;
77
78         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
79                 MaskSpline *spline;
80
81                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
82                         continue;
83                 }
84
85                 for (spline = masklay->splines.first; spline; spline = spline->next) {
86                         int i;
87                         MaskSplinePoint *cur_point;
88
89                         for (i = 0, cur_point = use_deform ? spline->points_deform : spline->points;
90                              i < spline->tot_point;
91                              i++, cur_point++)
92                         {
93                                 float *diff_points;
94                                 unsigned int tot_diff_point;
95
96                                 diff_points = BKE_mask_point_segment_diff_with_resolution(spline, cur_point, width, height,
97                                                                                           &tot_diff_point);
98
99                                 if (diff_points) {
100                                         int i, tot_point;
101                                         unsigned int tot_feather_point;
102                                         float *feather_points = NULL, *points;
103
104                                         if (feather) {
105                                                 feather_points = BKE_mask_point_segment_feather_diff_with_resolution(spline, cur_point,
106                                                                                                                      width, height,
107                                                                                                                      &tot_feather_point);
108
109                                                 points = feather_points;
110                                                 tot_point = tot_feather_point;
111                                         }
112                                         else {
113                                                 points = diff_points;
114                                                 tot_point = tot_diff_point;
115                                         }
116
117                                         for (i = 0; i < tot_point - 1; i++) {
118                                                 float cur_dist, a[2], b[2];
119
120                                                 a[0] = points[2 * i] * scalex;
121                                                 a[1] = points[2 * i + 1] * scaley;
122
123                                                 b[0] = points[2 * i + 2] * scalex;
124                                                 b[1] = points[2 * i + 3] * scaley;
125
126                                                 cur_dist = dist_to_line_segment_v2(co, a, b);
127
128                                                 if (point == NULL || cur_dist < dist) {
129                                                         if (tangent)
130                                                                 sub_v2_v2v2(tangent, &diff_points[2 * i + 2], &diff_points[2 * i]);
131
132                                                         point_masklay = masklay;
133                                                         point_spline = spline;
134                                                         point = use_deform ? &spline->points[(cur_point - spline->points_deform)] : cur_point;
135                                                         dist = cur_dist;
136                                                         u = (float)i / tot_point;
137
138                                                 }
139                                         }
140
141                                         if (feather_points)
142                                                 MEM_freeN(feather_points);
143
144                                         MEM_freeN(diff_points);
145                                 }
146                         }
147                 }
148         }
149
150         if (point && dist < threshold) {
151                 if (masklay_r)
152                         *masklay_r = point_masklay;
153
154                 if (spline_r)
155                         *spline_r = point_spline;
156
157                 if (point_r)
158                         *point_r = point;
159
160                 if (u_r) {
161                         u = BKE_mask_spline_project_co(point_spline, point, u, normal_co, MASK_PROJ_ANY);
162
163                         *u_r = u;
164                 }
165
166                 return TRUE;
167         }
168
169         if (masklay_r)
170                 *masklay_r = NULL;
171
172         if (spline_r)
173                 *spline_r = NULL;
174
175         if (point_r)
176                 *point_r = NULL;
177
178         return FALSE;
179 }
180
181 /******************** add vertex *********************/
182
183 static void setup_vertex_point(const bContext *C, Mask *mask, MaskSpline *spline, MaskSplinePoint *new_point,
184                                const float point_co[2], const float tangent[2], const float u,
185                                MaskSplinePoint *reference_point, const short reference_adjacent,
186                                const float view_zoom)
187 {
188         ScrArea *sa = CTX_wm_area(C);
189
190         MaskSplinePoint *prev_point = NULL;
191         MaskSplinePoint *next_point = NULL;
192         BezTriple *bezt;
193         int width, height;
194         float co[3];
195         const float len = 20.0; /* default length of handle in pixel space */
196
197         copy_v2_v2(co, point_co);
198         co[2] = 0.0f;
199
200         ED_mask_get_size(sa, &width, &height);
201
202         /* point coordinate */
203         bezt = &new_point->bezt;
204
205         bezt->h1 = bezt->h2 = HD_ALIGN;
206
207         if (reference_point) {
208                 bezt->h1 = bezt->h2 = MAX2(reference_point->bezt.h2, reference_point->bezt.h1);
209         }
210         else if (reference_adjacent) {
211                 if (spline->tot_point != 1) {
212                         int index = (int)(new_point - spline->points);
213                         prev_point = &spline->points[(index - 1) % spline->tot_point];
214                         next_point = &spline->points[(index + 1) % spline->tot_point];
215
216                         bezt->h1 = bezt->h2 = MAX2(prev_point->bezt.h2, next_point->bezt.h1);
217
218                         /* note, we may want to copy other attributes later, radius? pressure? color? */
219                 }
220         }
221
222         copy_v3_v3(bezt->vec[0], co);
223         copy_v3_v3(bezt->vec[1], co);
224         copy_v3_v3(bezt->vec[2], co);
225
226         /* initial offset for handles */
227         if (spline->tot_point == 1) {
228                 /* first point of splien is aligned horizontally */
229                 bezt->vec[0][0] -= len / maxi(width, height) * view_zoom;
230                 bezt->vec[2][0] += len / maxi(width, height) * view_zoom;
231         }
232         else if (tangent) {
233                 float vec[2];
234
235                 copy_v2_v2(vec, tangent);
236
237                 vec[0] *= width;
238                 vec[1] *= height;
239
240                 mul_v2_fl(vec, len / len_v2(vec));
241
242                 vec[0] /= width;
243                 vec[1] /= height;
244
245                 sub_v2_v2(bezt->vec[0], vec);
246                 add_v2_v2(bezt->vec[2], vec);
247
248                 if (reference_adjacent) {
249                         BKE_mask_calc_handle_adjacent_interp(spline, new_point, u);
250                 }
251         }
252         else {
253
254                 /* calculating auto handles works much nicer */
255 #if 0
256                 /* next points are aligning in the direction of previous/next point */
257                 MaskSplinePoint *point;
258                 float v1[2], v2[2], vec[2];
259                 float dir = 1.0f;
260
261                 if (new_point == spline->points) {
262                         point = new_point + 1;
263                         dir = -1.0f;
264                 }
265                 else
266                         point = new_point - 1;
267
268                 if (spline->tot_point < 3) {
269                         v1[0] = point->bezt.vec[1][0] * width;
270                         v1[1] = point->bezt.vec[1][1] * height;
271
272                         v2[0] = new_point->bezt.vec[1][0] * width;
273                         v2[1] = new_point->bezt.vec[1][1] * height;
274                 }
275                 else {
276                         if (new_point == spline->points) {
277                                 v1[0] = spline->points[1].bezt.vec[1][0] * width;
278                                 v1[1] = spline->points[1].bezt.vec[1][1] * height;
279
280                                 v2[0] = spline->points[spline->tot_point - 1].bezt.vec[1][0] * width;
281                                 v2[1] = spline->points[spline->tot_point - 1].bezt.vec[1][1] * height;
282                         }
283                         else {
284                                 v1[0] = spline->points[0].bezt.vec[1][0] * width;
285                                 v1[1] = spline->points[0].bezt.vec[1][1] * height;
286
287                                 v2[0] = spline->points[spline->tot_point - 2].bezt.vec[1][0] * width;
288                                 v2[1] = spline->points[spline->tot_point - 2].bezt.vec[1][1] * height;
289                         }
290                 }
291
292                 sub_v2_v2v2(vec, v1, v2);
293                 mul_v2_fl(vec, len * dir / len_v2(vec));
294
295                 vec[0] /= width;
296                 vec[1] /= height;
297
298                 add_v2_v2(bezt->vec[0], vec);
299                 sub_v2_v2(bezt->vec[2], vec);
300 #else
301                 BKE_mask_calc_handle_point_auto(spline, new_point, TRUE);
302                 BKE_mask_calc_handle_adjacent_interp(spline, new_point, u);
303
304 #endif
305         }
306
307         BKE_mask_parent_init(&new_point->parent);
308
309         /* select new point */
310         MASKPOINT_SEL_ALL(new_point);
311         ED_mask_select_flush_all(mask);
312 }
313
314
315 /* **** add extrude vertex **** */
316
317 static void finSelectedSplinePoint(MaskLayer *masklay, MaskSpline **spline, MaskSplinePoint **point, short check_active)
318 {
319         MaskSpline *cur_spline = masklay->splines.first;
320
321         *spline = NULL;
322         *point = NULL;
323
324         if (check_active) {
325                 /* TODO, having an active point but no active spline is possible, why? */
326                 if (masklay->act_spline && masklay->act_point && MASKPOINT_ISSEL_ANY(masklay->act_point)) {
327                         *spline = masklay->act_spline;
328                         *point = masklay->act_point;
329                         return;
330                 }
331         }
332
333         while (cur_spline) {
334                 int i;
335
336                 for (i = 0; i < cur_spline->tot_point; i++) {
337                         MaskSplinePoint *cur_point = &cur_spline->points[i];
338
339                         if (MASKPOINT_ISSEL_ANY(cur_point)) {
340                                 if (*spline != NULL && *spline != cur_spline) {
341                                         *spline = NULL;
342                                         *point = NULL;
343                                         return;
344                                 }
345                                 else if (*point) {
346                                         *point = NULL;
347                                 }
348                                 else {
349                                         *spline = cur_spline;
350                                         *point = cur_point;
351                                 }
352                         }
353                 }
354
355                 cur_spline = cur_spline->next;
356         }
357 }
358
359 /* **** add subdivide vertex **** */
360
361 static void mask_spline_add_point_at_index(MaskSpline *spline, int point_index)
362 {
363         MaskSplinePoint *new_point_array;
364
365         new_point_array = MEM_callocN(sizeof(MaskSplinePoint) * (spline->tot_point + 1), "add mask vert points");
366
367         memcpy(new_point_array, spline->points, sizeof(MaskSplinePoint) * (point_index + 1));
368         memcpy(new_point_array + point_index + 2, spline->points + point_index + 1,
369                sizeof(MaskSplinePoint) * (spline->tot_point - point_index - 1));
370
371         MEM_freeN(spline->points);
372         spline->points = new_point_array;
373         spline->tot_point++;
374 }
375
376 static int add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2])
377 {
378         MaskLayer *masklay;
379         MaskSpline *spline;
380         MaskSplinePoint *point = NULL;
381         const float threshold = 9;
382         float tangent[2];
383         float u;
384
385         if (find_nearest_diff_point(C, mask, co, threshold, FALSE, &masklay, &spline, &point, &u, tangent, TRUE)) {
386                 MaskSplinePoint *new_point;
387                 int point_index = point - spline->points;
388
389                 ED_mask_select_toggle_all(mask, SEL_DESELECT);
390
391                 mask_spline_add_point_at_index(spline, point_index);
392
393                 new_point = &spline->points[point_index + 1];
394
395                 setup_vertex_point(C, mask, spline, new_point, co, tangent, u, NULL, TRUE, 1.0f);
396
397                 /* TODO - we could pass the spline! */
398                 BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index + 1, TRUE, TRUE);
399
400                 masklay->act_point = new_point;
401
402                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
403
404                 return TRUE;
405         }
406
407         return FALSE;
408 }
409
410 static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2])
411 {
412         MaskSpline *spline;
413         MaskSplinePoint *point;
414         MaskSplinePoint *new_point = NULL, *ref_point = NULL;
415
416         /* check on which side we want to add the point */
417         int point_index;
418         float tangent_point[2];
419         float tangent_co[2];
420         int do_cyclic_correct = FALSE;
421         int do_recalc_src = FALSE;  /* when extruding from endpoints only */
422         int do_prev;                /* use prev point rather then next?? */
423
424         if (!masklay) {
425                 return FALSE;
426         }
427         else {
428                 finSelectedSplinePoint(masklay, &spline, &point, TRUE);
429         }
430
431         ED_mask_select_toggle_all(mask, SEL_DESELECT);
432
433         point_index = (point - spline->points);
434
435         MASKPOINT_DESEL_ALL(point);
436
437         if ((spline->flag & MASK_SPLINE_CYCLIC) ||
438             (point_index > 0 && point_index != spline->tot_point - 1))
439         {
440                 BKE_mask_calc_tangent_polyline(spline, point, tangent_point);
441                 sub_v2_v2v2(tangent_co, co, point->bezt.vec[1]);
442
443                 if (dot_v2v2(tangent_point, tangent_co) < 0.0f) {
444                         do_prev = TRUE;
445                 }
446                 else {
447                         do_prev = FALSE;
448                 }
449         }
450         else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == 0)) {
451                 do_prev = TRUE;
452                 do_recalc_src = TRUE;
453         }
454         else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == spline->tot_point - 1)) {
455                 do_prev = FALSE;
456                 do_recalc_src = TRUE;
457         }
458         else {
459                 do_prev = FALSE;  /* quiet warning */
460                 /* should never get here */
461                 BLI_assert(0);
462         }
463
464         /* use the point before the active one */
465         if (do_prev) {
466                 point_index--;
467                 if (point_index < 0) {
468                         point_index += spline->tot_point; /* wrap index */
469                         if ((spline->flag & MASK_SPLINE_CYCLIC) == 0) {
470                                 do_cyclic_correct = TRUE;
471                                 point_index = 0;
472                         }
473                 }
474         }
475
476 //              print_v2("", tangent_point);
477 //              printf("%d\n", point_index);
478
479         mask_spline_add_point_at_index(spline, point_index);
480
481         if (do_cyclic_correct) {
482                 ref_point = &spline->points[point_index + 1];
483                 new_point = &spline->points[point_index];
484                 *ref_point = *new_point;
485                 memset(new_point, 0, sizeof(*new_point));
486         }
487         else {
488                 ref_point = &spline->points[point_index];
489                 new_point = &spline->points[point_index + 1];
490         }
491
492         masklay->act_point = new_point;
493
494         setup_vertex_point(C, mask, spline, new_point, co, NULL, 0.5f, ref_point, FALSE, 1.0f);
495
496         if (masklay->splines_shapes.first) {
497                 point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
498                 BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index, TRUE, TRUE);
499         }
500
501         if (do_recalc_src) {
502                 /* TODO, update keyframes in time */
503                 BKE_mask_calc_handle_point_auto(spline, ref_point, FALSE);
504         }
505
506         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
507
508         return TRUE;
509 }
510
511 static int add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2])
512 {
513         MaskSpline *spline;
514         MaskSplinePoint *point;
515         MaskSplinePoint *new_point = NULL, *ref_point = NULL;
516         float view_zoom;
517
518         if (!masklay) {
519                 /* if there's no masklay currently operationg on, create new one */
520                 masklay = BKE_mask_layer_new(mask, "");
521                 mask->masklay_act = mask->masklay_tot - 1;
522                 spline = NULL;
523                 point = NULL;
524         }
525         else {
526                 finSelectedSplinePoint(masklay, &spline, &point, TRUE);
527         }
528
529         ED_mask_select_toggle_all(mask, SEL_DESELECT);
530
531         if (!spline) {
532                 /* no selected splines in active masklay, create new spline */
533                 spline = BKE_mask_spline_add(masklay);
534         }
535
536         masklay->act_spline = spline;
537         new_point = spline->points;
538
539         masklay->act_point = new_point;
540
541         {
542                 ScrArea *sa = CTX_wm_area(C);
543                 ARegion *ar = CTX_wm_region(C);
544
545                 /* calc view zoom in a simplistic way */
546                 float co_a[2];
547                 float co_b[2];
548                 int mval_a[2] = {0, 0};
549                 int mval_b[2] = {1, 1};
550
551                 ED_mask_mouse_pos(sa, ar, mval_a, co_a);
552                 ED_mask_mouse_pos(sa, ar, mval_b, co_b);
553
554                 view_zoom = ((co_b[0] - co_a[0]) + (co_b[1] - co_a[1])) / 2.0f;
555
556                 /* scale up - arbitrarty but works well in the view */
557                 view_zoom *= 200.0f;
558         }
559
560         setup_vertex_point(C, mask, spline, new_point, co, NULL, 0.5f, ref_point, FALSE, view_zoom);
561
562         {
563                 int point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
564                 BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index, TRUE, TRUE);
565         }
566
567         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
568
569         return TRUE;
570 }
571
572 static int add_vertex_exec(bContext *C, wmOperator *op)
573 {
574         Mask *mask = CTX_data_edit_mask(C);
575         MaskLayer *masklay;
576
577         float co[2];
578
579         masklay = BKE_mask_layer_active(mask);
580
581         if (masklay && masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
582                 masklay = NULL;
583         }
584
585         RNA_float_get_array(op->ptr, "location", co);
586
587         /* TODO, having an active point but no active spline is possible, why? */
588         if (masklay && masklay->act_spline && masklay->act_point && MASKPOINT_ISSEL_ANY(masklay->act_point)) {
589
590                 /* cheap trick - double click for cyclic */
591                 MaskSpline *spline = masklay->act_spline;
592                 MaskSplinePoint *point = masklay->act_point;
593
594                 int is_sta = (point == spline->points);
595                 int is_end = (point == &spline->points[spline->tot_point - 1]);
596
597                 /* then check are we overlapping the mouse */
598                 if ((is_sta || is_end) && equals_v2v2(co, point->bezt.vec[1])) {
599                         if (spline->flag & MASK_SPLINE_CYCLIC) {
600                                 /* nothing to do */
601                                 return OPERATOR_CANCELLED;
602                         }
603                         else {
604                                 /* recalc the connecting point as well to make a nice even curve */
605                                 MaskSplinePoint *point_other = is_end ? spline->points : &spline->points[spline->tot_point - 1];
606                                 spline->flag |= MASK_SPLINE_CYCLIC;
607
608                                 /* TODO, update keyframes in time */
609                                 BKE_mask_calc_handle_point_auto(spline, point, FALSE);
610                                 BKE_mask_calc_handle_point_auto(spline, point_other, FALSE);
611
612                                 /* TODO: only update this spline */
613                                 BKE_mask_update_display(mask, CTX_data_scene(C)->r.cfra);
614
615                                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
616                                 return OPERATOR_FINISHED;
617                         }
618                 }
619
620                 if (!add_vertex_subdivide(C, mask, co)) {
621                         if (!add_vertex_extrude(C, mask, masklay, co)) {
622                                 return OPERATOR_CANCELLED;
623                         }
624                 }
625         }
626         else {
627                 if (!add_vertex_subdivide(C, mask, co)) {
628                         if (!add_vertex_new(C, mask, masklay, co)) {
629                                 return OPERATOR_CANCELLED;
630                         }
631                 }
632         }
633
634         /* TODO: only update this spline */
635         BKE_mask_update_display(mask, CTX_data_scene(C)->r.cfra);
636
637         return OPERATOR_FINISHED;
638 }
639
640 static int add_vertex_invoke(bContext *C, wmOperator *op, wmEvent *event)
641 {
642         ScrArea *sa = CTX_wm_area(C);
643         ARegion *ar = CTX_wm_region(C);
644
645         float co[2];
646
647         ED_mask_mouse_pos(sa, ar, event->mval, co);
648
649         RNA_float_set_array(op->ptr, "location", co);
650
651         return add_vertex_exec(C, op);
652 }
653
654 void MASK_OT_add_vertex(wmOperatorType *ot)
655 {
656         /* identifiers */
657         ot->name = "Add Vertex";
658         ot->description = "Add vertex to active spline";
659         ot->idname = "MASK_OT_add_vertex";
660
661         /* api callbacks */
662         ot->exec = add_vertex_exec;
663         ot->invoke = add_vertex_invoke;
664         ot->poll = ED_maskedit_mask_poll;
665
666         /* flags */
667         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
668
669         /* properties */
670         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
671                              "Location", "Location of vertex in normalized space", -1.0f, 1.0f);
672 }
673
674 /******************** add feather vertex *********************/
675
676 static int add_feather_vertex_exec(bContext *C, wmOperator *op)
677 {
678         Mask *mask = CTX_data_edit_mask(C);
679         MaskLayer *masklay;
680         MaskSpline *spline;
681         MaskSplinePoint *point = NULL;
682         const float threshold = 9;
683         float co[2], u;
684
685         RNA_float_get_array(op->ptr, "location", co);
686
687         point = ED_mask_point_find_nearest(C, mask, co, threshold, NULL, NULL, NULL, NULL);
688         if (point)
689                 return OPERATOR_FINISHED;
690
691         if (find_nearest_diff_point(C, mask, co, threshold, TRUE, &masklay, &spline, &point, &u, NULL, TRUE)) {
692                 Scene *scene = CTX_data_scene(C);
693                 float w = BKE_mask_point_weight(spline, point, u);
694                 float weight_scalar = BKE_mask_point_weight_scalar(spline, point, u);
695
696                 if (weight_scalar != 0.0f) {
697                         w = w / weight_scalar;
698                 }
699
700                 BKE_mask_point_add_uw(point, u, w);
701
702                 BKE_mask_update_display(mask, scene->r.cfra);
703
704                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
705
706                 DAG_id_tag_update(&mask->id, 0);
707
708                 return OPERATOR_FINISHED;
709         }
710
711         return OPERATOR_CANCELLED;
712 }
713
714 static int add_feather_vertex_invoke(bContext *C, wmOperator *op, wmEvent *event)
715 {
716         ScrArea *sa = CTX_wm_area(C);
717         ARegion *ar = CTX_wm_region(C);
718
719         float co[2];
720
721         ED_mask_mouse_pos(sa, ar, event->mval, co);
722
723         RNA_float_set_array(op->ptr, "location", co);
724
725         return add_feather_vertex_exec(C, op);
726 }
727
728 void MASK_OT_add_feather_vertex(wmOperatorType *ot)
729 {
730         /* identifiers */
731         ot->name = "Add feather Vertex";
732         ot->description = "Add vertex to feather";
733         ot->idname = "MASK_OT_add_feather_vertex";
734
735         /* api callbacks */
736         ot->exec = add_feather_vertex_exec;
737         ot->invoke = add_feather_vertex_invoke;
738         ot->poll = ED_maskedit_mask_poll;
739
740         /* flags */
741         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
742
743         /* properties */
744         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
745                              "Location", "Location of vertex in normalized space", -1.0f, 1.0f);
746 }