Implement asymmetric and free handles type for masks
[blender-staging.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 #include "ED_screen.h"
50
51 #include "RNA_access.h"
52 #include "RNA_define.h"
53
54 #include "mask_intern.h"  /* own include */
55
56
57 static int find_nearest_diff_point(const bContext *C, Mask *mask, const float normal_co[2], int threshold, int feather,
58                                    MaskLayer **masklay_r, MaskSpline **spline_r, MaskSplinePoint **point_r,
59                                    float *u_r, float tangent[2],
60                                    const short use_deform)
61 {
62         ScrArea *sa = CTX_wm_area(C);
63         ARegion *ar = CTX_wm_region(C);
64
65         MaskLayer *masklay, *point_masklay;
66         MaskSpline *point_spline;
67         MaskSplinePoint *point = NULL;
68         float dist = FLT_MAX, co[2];
69         int width, height;
70         float u;
71         float scalex, scaley;
72
73         ED_mask_get_size(sa, &width, &height);
74         ED_mask_pixelspace_factor(sa, ar, &scalex, &scaley);
75
76         co[0] = normal_co[0] * scalex;
77         co[1] = normal_co[1] * scaley;
78
79         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
80                 MaskSpline *spline;
81
82                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
83                         continue;
84                 }
85
86                 for (spline = masklay->splines.first; spline; spline = spline->next) {
87                         int i;
88                         MaskSplinePoint *cur_point;
89
90                         for (i = 0, cur_point = use_deform ? spline->points_deform : spline->points;
91                              i < spline->tot_point;
92                              i++, cur_point++)
93                         {
94                                 float *diff_points;
95                                 unsigned int tot_diff_point;
96
97                                 diff_points = BKE_mask_point_segment_diff(spline, cur_point, width, height,
98                                                                           &tot_diff_point);
99
100                                 if (diff_points) {
101                                         int j, tot_point;
102                                         unsigned int tot_feather_point;
103                                         float *feather_points = NULL, *points;
104
105                                         if (feather) {
106                                                 feather_points = BKE_mask_point_segment_feather_diff(spline, cur_point,
107                                                                                                      width, height,
108                                                                                                      &tot_feather_point);
109
110                                                 points = feather_points;
111                                                 tot_point = tot_feather_point;
112                                         }
113                                         else {
114                                                 points = diff_points;
115                                                 tot_point = tot_diff_point;
116                                         }
117
118                                         for (j = 0; j < tot_point - 1; j++) {
119                                                 float cur_dist, a[2], b[2];
120
121                                                 a[0] = points[2 * j] * scalex;
122                                                 a[1] = points[2 * j + 1] * scaley;
123
124                                                 b[0] = points[2 * j + 2] * scalex;
125                                                 b[1] = points[2 * j + 3] * scaley;
126
127                                                 cur_dist = dist_to_line_segment_v2(co, a, b);
128
129                                                 if (cur_dist < dist) {
130                                                         if (tangent)
131                                                                 sub_v2_v2v2(tangent, &diff_points[2 * j + 2], &diff_points[2 * j]);
132
133                                                         point_masklay = masklay;
134                                                         point_spline = spline;
135                                                         point = use_deform ? &spline->points[(cur_point - spline->points_deform)] : cur_point;
136                                                         dist = cur_dist;
137                                                         u = (float)j / tot_point;
138
139                                                 }
140                                         }
141
142                                         if (feather_points)
143                                                 MEM_freeN(feather_points);
144
145                                         MEM_freeN(diff_points);
146                                 }
147                         }
148                 }
149         }
150
151         if (point && dist < threshold) {
152                 if (masklay_r)
153                         *masklay_r = point_masklay;
154
155                 if (spline_r)
156                         *spline_r = point_spline;
157
158                 if (point_r)
159                         *point_r = point;
160
161                 if (u_r) {
162                         u = BKE_mask_spline_project_co(point_spline, point, u, normal_co, MASK_PROJ_ANY);
163
164                         *u_r = u;
165                 }
166
167                 return TRUE;
168         }
169
170         if (masklay_r)
171                 *masklay_r = NULL;
172
173         if (spline_r)
174                 *spline_r = NULL;
175
176         if (point_r)
177                 *point_r = NULL;
178
179         return FALSE;
180 }
181
182 /******************** add vertex *********************/
183
184 static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *new_point,
185                                const float point_co[2], const float u,
186                                MaskSplinePoint *reference_point, const short reference_adjacent)
187 {
188         MaskSplinePoint *prev_point = NULL;
189         MaskSplinePoint *next_point = NULL;
190         BezTriple *bezt;
191         float co[3];
192
193         copy_v2_v2(co, point_co);
194         co[2] = 0.0f;
195
196         /* point coordinate */
197         bezt = &new_point->bezt;
198
199         bezt->h1 = bezt->h2 = HD_ALIGN;
200
201         if (reference_point) {
202                 if (reference_point->bezt.h1 == HD_VECT && reference_point->bezt.h2 == HD_VECT) {
203                         /* If the reference point is sharp try using some smooth point as reference
204                          * for handles.
205                          */
206                         int point_index = reference_point - spline->points;
207                         int delta = new_point == spline->points ? 1 : -1;
208                         int i = 0;
209                         for (i = 0; i < spline->tot_point - 1; ++i) {
210                                 MaskSplinePoint *current_point;
211
212                                 point_index += delta;
213                                 if (point_index == -1 || point_index >= spline->tot_point) {
214                                         if (spline->flag & MASK_SPLINE_CYCLIC) {
215                                                 if (point_index == -1) {
216                                                         point_index = spline->tot_point - 1;
217                                                 }
218                                                 else if (point_index >= spline->tot_point) {
219                                                         point_index = 0;
220                                                 }
221                                         }
222                                         else {
223                                                 break;
224                                         }
225                                 }
226
227                                 current_point = &spline->points[point_index];
228                                 if (current_point->bezt.h1 != HD_VECT || current_point->bezt.h2 != HD_VECT) {
229                                         bezt->h1 = bezt->h2 = MAX2(current_point->bezt.h2, current_point->bezt.h1);
230                                         break;
231                                 }
232                         }
233                 }
234                 else {
235                         bezt->h1 = bezt->h2 = MAX2(reference_point->bezt.h2, reference_point->bezt.h1);
236                 }
237         }
238         else if (reference_adjacent) {
239                 if (spline->tot_point != 1) {
240                         int index = (int)(new_point - spline->points);
241                         prev_point = &spline->points[(index - 1) % spline->tot_point];
242                         next_point = &spline->points[(index + 1) % spline->tot_point];
243
244                         bezt->h1 = bezt->h2 = MAX2(prev_point->bezt.h2, next_point->bezt.h1);
245
246                         /* note, we may want to copy other attributes later, radius? pressure? color? */
247                 }
248         }
249
250         copy_v3_v3(bezt->vec[0], co);
251         copy_v3_v3(bezt->vec[1], co);
252         copy_v3_v3(bezt->vec[2], co);
253
254         BKE_mask_parent_init(&new_point->parent);
255         if (spline->tot_point != 1) {
256                 BKE_mask_calc_handle_adjacent_interp(spline, new_point, u);
257         }
258
259         /* select new point */
260         MASKPOINT_SEL_ALL(new_point);
261         ED_mask_select_flush_all(mask);
262 }
263
264
265 /* **** add extrude vertex **** */
266
267 static void finSelectedSplinePoint(MaskLayer *masklay, MaskSpline **spline, MaskSplinePoint **point, short check_active)
268 {
269         MaskSpline *cur_spline = masklay->splines.first;
270
271         *spline = NULL;
272         *point = NULL;
273
274         if (check_active) {
275                 /* TODO, having an active point but no active spline is possible, why? */
276                 if (masklay->act_spline && masklay->act_point && MASKPOINT_ISSEL_ANY(masklay->act_point)) {
277                         *spline = masklay->act_spline;
278                         *point = masklay->act_point;
279                         return;
280                 }
281         }
282
283         while (cur_spline) {
284                 int i;
285
286                 for (i = 0; i < cur_spline->tot_point; i++) {
287                         MaskSplinePoint *cur_point = &cur_spline->points[i];
288
289                         if (MASKPOINT_ISSEL_ANY(cur_point)) {
290                                 if (*spline != NULL && *spline != cur_spline) {
291                                         *spline = NULL;
292                                         *point = NULL;
293                                         return;
294                                 }
295                                 else if (*point) {
296                                         *point = NULL;
297                                 }
298                                 else {
299                                         *spline = cur_spline;
300                                         *point = cur_point;
301                                 }
302                         }
303                 }
304
305                 cur_spline = cur_spline->next;
306         }
307 }
308
309 /* **** add subdivide vertex **** */
310
311 static void mask_spline_add_point_at_index(MaskSpline *spline, int point_index)
312 {
313         MaskSplinePoint *new_point_array;
314
315         new_point_array = MEM_callocN(sizeof(MaskSplinePoint) * (spline->tot_point + 1), "add mask vert points");
316
317         memcpy(new_point_array, spline->points, sizeof(MaskSplinePoint) * (point_index + 1));
318         memcpy(new_point_array + point_index + 2, spline->points + point_index + 1,
319                sizeof(MaskSplinePoint) * (spline->tot_point - point_index - 1));
320
321         MEM_freeN(spline->points);
322         spline->points = new_point_array;
323         spline->tot_point++;
324 }
325
326 static int add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2])
327 {
328         MaskLayer *masklay;
329         MaskSpline *spline;
330         MaskSplinePoint *point = NULL;
331         const float threshold = 9;
332         float tangent[2];
333         float u;
334
335         if (find_nearest_diff_point(C, mask, co, threshold, FALSE, &masklay, &spline, &point, &u, tangent, TRUE)) {
336                 MaskSplinePoint *new_point;
337                 int point_index = point - spline->points;
338
339                 ED_mask_select_toggle_all(mask, SEL_DESELECT);
340
341                 mask_spline_add_point_at_index(spline, point_index);
342
343                 new_point = &spline->points[point_index + 1];
344
345                 setup_vertex_point(mask, spline, new_point, co, u, NULL, TRUE);
346
347                 /* TODO - we could pass the spline! */
348                 BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index + 1, true, true);
349
350                 masklay->act_spline = spline;
351                 masklay->act_point = new_point;
352
353                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
354
355                 return TRUE;
356         }
357
358         return FALSE;
359 }
360
361 static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2])
362 {
363         MaskSpline *spline;
364         MaskSplinePoint *point;
365         MaskSplinePoint *new_point = NULL, *ref_point = NULL;
366
367         /* check on which side we want to add the point */
368         int point_index;
369         float tangent_point[2];
370         float tangent_co[2];
371         bool do_cyclic_correct = false;
372         bool do_prev;                /* use prev point rather then next?? */
373
374         if (!masklay) {
375                 return FALSE;
376         }
377         else {
378                 finSelectedSplinePoint(masklay, &spline, &point, TRUE);
379         }
380
381         ED_mask_select_toggle_all(mask, SEL_DESELECT);
382
383         point_index = (point - spline->points);
384
385         MASKPOINT_DESEL_ALL(point);
386
387         if ((spline->flag & MASK_SPLINE_CYCLIC) ||
388             (point_index > 0 && point_index != spline->tot_point - 1))
389         {
390                 BKE_mask_calc_tangent_polyline(spline, point, tangent_point);
391                 sub_v2_v2v2(tangent_co, co, point->bezt.vec[1]);
392
393                 if (dot_v2v2(tangent_point, tangent_co) < 0.0f) {
394                         do_prev = TRUE;
395                 }
396                 else {
397                         do_prev = FALSE;
398                 }
399         }
400         else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == 0)) {
401                 do_prev = TRUE;
402         }
403         else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == spline->tot_point - 1)) {
404                 do_prev = FALSE;
405         }
406         else {
407                 do_prev = FALSE;  /* quiet warning */
408                 /* should never get here */
409                 BLI_assert(0);
410         }
411
412         /* use the point before the active one */
413         if (do_prev) {
414                 point_index--;
415                 if (point_index < 0) {
416                         point_index += spline->tot_point; /* wrap index */
417                         if ((spline->flag & MASK_SPLINE_CYCLIC) == 0) {
418                                 do_cyclic_correct = TRUE;
419                                 point_index = 0;
420                         }
421                 }
422         }
423
424 //              print_v2("", tangent_point);
425 //              printf("%d\n", point_index);
426
427         mask_spline_add_point_at_index(spline, point_index);
428
429         if (do_cyclic_correct) {
430                 ref_point = &spline->points[point_index + 1];
431                 new_point = &spline->points[point_index];
432                 *ref_point = *new_point;
433                 memset(new_point, 0, sizeof(*new_point));
434         }
435         else {
436                 ref_point = &spline->points[point_index];
437                 new_point = &spline->points[point_index + 1];
438         }
439
440         masklay->act_point = new_point;
441
442         setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, FALSE);
443
444         if (masklay->splines_shapes.first) {
445                 point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
446                 BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index, true, true);
447         }
448
449         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
450
451         return TRUE;
452 }
453
454 static int add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2])
455 {
456         MaskSpline *spline;
457         MaskSplinePoint *point;
458         MaskSplinePoint *new_point = NULL, *ref_point = NULL;
459
460         if (!masklay) {
461                 /* if there's no masklay currently operationg on, create new one */
462                 masklay = BKE_mask_layer_new(mask, "");
463                 mask->masklay_act = mask->masklay_tot - 1;
464                 spline = NULL;
465                 point = NULL;
466         }
467         else {
468                 finSelectedSplinePoint(masklay, &spline, &point, TRUE);
469         }
470
471         ED_mask_select_toggle_all(mask, SEL_DESELECT);
472
473         if (!spline) {
474                 /* no selected splines in active masklay, create new spline */
475                 spline = BKE_mask_spline_add(masklay);
476         }
477
478         masklay->act_spline = spline;
479         new_point = spline->points;
480
481         masklay->act_point = new_point;
482
483         setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, FALSE);
484
485         {
486                 int point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
487                 BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index, true, true);
488         }
489
490         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
491
492         return TRUE;
493 }
494
495 static int add_vertex_exec(bContext *C, wmOperator *op)
496 {
497         Scene *scene = CTX_data_scene(C);
498         Mask *mask = CTX_data_edit_mask(C);
499         MaskLayer *masklay;
500
501         float co[2];
502
503         if (mask == NULL) {
504                 /* if there's no active mask, create one */
505                 mask = ED_mask_new(C, NULL);
506         }
507
508         masklay = BKE_mask_layer_active(mask);
509
510         if (masklay && masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
511                 masklay = NULL;
512         }
513
514         RNA_float_get_array(op->ptr, "location", co);
515
516         /* TODO, having an active point but no active spline is possible, why? */
517         if (masklay && masklay->act_spline && masklay->act_point && MASKPOINT_ISSEL_ANY(masklay->act_point)) {
518
519                 /* cheap trick - double click for cyclic */
520                 MaskSpline *spline = masklay->act_spline;
521                 MaskSplinePoint *point = masklay->act_point;
522
523                 const bool is_sta = (point == spline->points);
524                 const bool is_end = (point == &spline->points[spline->tot_point - 1]);
525
526                 /* then check are we overlapping the mouse */
527                 if ((is_sta || is_end) && equals_v2v2(co, point->bezt.vec[1])) {
528                         if (spline->flag & MASK_SPLINE_CYCLIC) {
529                                 /* nothing to do */
530                                 return OPERATOR_CANCELLED;
531                         }
532                         else {
533                                 /* recalc the connecting point as well to make a nice even curve */
534                                 MaskSplinePoint *point_other = is_end ? spline->points : &spline->points[spline->tot_point - 1];
535                                 spline->flag |= MASK_SPLINE_CYCLIC;
536
537                                 /* TODO, update keyframes in time */
538                                 BKE_mask_calc_handle_point_auto(spline, point, FALSE);
539                                 BKE_mask_calc_handle_point_auto(spline, point_other, FALSE);
540
541                                 /* TODO: only update this spline */
542                                 BKE_mask_update_display(mask, CFRA);
543
544                                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
545                                 return OPERATOR_FINISHED;
546                         }
547                 }
548
549                 if (!add_vertex_subdivide(C, mask, co)) {
550                         if (!add_vertex_extrude(C, mask, masklay, co)) {
551                                 return OPERATOR_CANCELLED;
552                         }
553                 }
554         }
555         else {
556                 if (!add_vertex_subdivide(C, mask, co)) {
557                         if (!add_vertex_new(C, mask, masklay, co)) {
558                                 return OPERATOR_CANCELLED;
559                         }
560                 }
561         }
562
563         /* TODO: only update this spline */
564         BKE_mask_update_display(mask, CFRA);
565
566         return OPERATOR_FINISHED;
567 }
568
569 static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
570 {
571         ScrArea *sa = CTX_wm_area(C);
572         ARegion *ar = CTX_wm_region(C);
573
574         float co[2];
575
576         ED_mask_mouse_pos(sa, ar, event->mval, co);
577
578         RNA_float_set_array(op->ptr, "location", co);
579
580         return add_vertex_exec(C, op);
581 }
582
583 void MASK_OT_add_vertex(wmOperatorType *ot)
584 {
585         /* identifiers */
586         ot->name = "Add Vertex";
587         ot->description = "Add vertex to active spline";
588         ot->idname = "MASK_OT_add_vertex";
589
590         /* api callbacks */
591         ot->exec = add_vertex_exec;
592         ot->invoke = add_vertex_invoke;
593         ot->poll = ED_operator_mask;
594
595         /* flags */
596         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
597
598         /* properties */
599         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
600                              "Location", "Location of vertex in normalized space", -1.0f, 1.0f);
601 }
602
603 /******************** add feather vertex *********************/
604
605 static int add_feather_vertex_exec(bContext *C, wmOperator *op)
606 {
607         Mask *mask = CTX_data_edit_mask(C);
608         MaskLayer *masklay;
609         MaskSpline *spline;
610         MaskSplinePoint *point = NULL;
611         const float threshold = 9;
612         float co[2], u;
613
614         RNA_float_get_array(op->ptr, "location", co);
615
616         point = ED_mask_point_find_nearest(C, mask, co, threshold, NULL, NULL, NULL, NULL);
617         if (point)
618                 return OPERATOR_FINISHED;
619
620         if (find_nearest_diff_point(C, mask, co, threshold, TRUE, &masklay, &spline, &point, &u, NULL, TRUE)) {
621                 Scene *scene = CTX_data_scene(C);
622                 float w = BKE_mask_point_weight(spline, point, u);
623                 float weight_scalar = BKE_mask_point_weight_scalar(spline, point, u);
624
625                 if (weight_scalar != 0.0f) {
626                         w = w / weight_scalar;
627                 }
628
629                 BKE_mask_point_add_uw(point, u, w);
630
631                 BKE_mask_update_display(mask, scene->r.cfra);
632
633                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
634
635                 DAG_id_tag_update(&mask->id, 0);
636
637                 return OPERATOR_FINISHED;
638         }
639
640         return OPERATOR_CANCELLED;
641 }
642
643 static int add_feather_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
644 {
645         ScrArea *sa = CTX_wm_area(C);
646         ARegion *ar = CTX_wm_region(C);
647
648         float co[2];
649
650         ED_mask_mouse_pos(sa, ar, event->mval, co);
651
652         RNA_float_set_array(op->ptr, "location", co);
653
654         return add_feather_vertex_exec(C, op);
655 }
656
657 void MASK_OT_add_feather_vertex(wmOperatorType *ot)
658 {
659         /* identifiers */
660         ot->name = "Add Feather Vertex";
661         ot->description = "Add vertex to feather";
662         ot->idname = "MASK_OT_add_feather_vertex";
663
664         /* api callbacks */
665         ot->exec = add_feather_vertex_exec;
666         ot->invoke = add_feather_vertex_invoke;
667         ot->poll = ED_maskedit_mask_poll;
668
669         /* flags */
670         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
671
672         /* properties */
673         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
674                              "Location", "Location of vertex in normalized space", -1.0f, 1.0f);
675 }
676
677 /******************** common primitive functions *********************/
678
679 static int create_primitive_from_points(bContext *C, wmOperator *op, const float (*points)[2],
680                                         int num_points, char handle_type)
681 {
682         ScrArea *sa = CTX_wm_area(C);
683         Scene *scene = CTX_data_scene(C);
684         Mask *mask;
685         MaskLayer *mask_layer;
686         MaskSpline *new_spline;
687         float scale, location[2], frame_size[2];
688         int i, width, height;
689         int size = RNA_float_get(op->ptr, "size");
690
691         ED_mask_get_size(sa, &width, &height);
692         scale = (float)size / max_ii(width, height);
693
694         /* Get location in mask space. */
695         frame_size[0] = width;
696         frame_size[1] = height;
697         RNA_float_get_array(op->ptr, "location", location);
698         location[0] /= width;
699         location[1] /= height;
700         BKE_mask_coord_from_frame(location, location, frame_size);
701
702         /* Make it so new primitive is centered to mouse location. */
703         location[0] -= 0.5f * scale;
704         location[1] -= 0.5f * scale;
705
706         mask_layer = ED_mask_layer_ensure(C);
707         mask = CTX_data_edit_mask(C);
708
709         ED_mask_select_toggle_all(mask, SEL_DESELECT);
710
711         new_spline = BKE_mask_spline_add(mask_layer);
712         new_spline->flag = MASK_SPLINE_CYCLIC | SELECT;
713         new_spline->tot_point = num_points;
714         new_spline->points = MEM_recallocN(new_spline->points,
715                                            sizeof(MaskSplinePoint) * new_spline->tot_point);
716
717         mask_layer->act_spline = new_spline;
718         mask_layer->act_point = NULL;
719
720         for (i = 0; i < num_points; i++) {
721                 MaskSplinePoint *new_point = &new_spline->points[i];
722
723                 copy_v2_v2(new_point->bezt.vec[1], points[i]);
724                 mul_v2_fl(new_point->bezt.vec[1], scale);
725                 add_v2_v2(new_point->bezt.vec[1], location);
726
727                 new_point->bezt.h1 = handle_type;
728                 new_point->bezt.h2 = handle_type;
729                 BKE_mask_point_select_set(new_point, true);
730         }
731
732         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
733
734         /* TODO: only update this spline */
735         BKE_mask_update_display(mask, CFRA);
736
737         return OPERATOR_FINISHED;
738 }
739
740 static int primitive_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
741 {
742         ScrArea *sa = CTX_wm_area(C);
743         float cursor[2];
744         int width, height;
745
746         ED_mask_get_size(sa, &width, &height);
747         ED_mask_cursor_location_get(sa, cursor);
748
749         cursor[0] *= width;
750         cursor[1] *= height;
751
752         RNA_float_set_array(op->ptr, "location", cursor);
753
754         return op->type->exec(C, op);
755 }
756
757 static void define_prinitive_add_properties(wmOperatorType *ot)
758 {
759         RNA_def_float(ot->srna, "size", 100, -FLT_MAX, FLT_MAX,
760                              "Size", "Size of new circle", -FLT_MAX, FLT_MAX);
761         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
762                              "Location", "Location of new circle", -FLT_MAX, FLT_MAX);
763 }
764
765 /******************** primitive add circle *********************/
766
767 static int primitive_circle_add_exec(bContext *C, wmOperator *op)
768 {
769         const float points[4][2] = {{0.0f, 0.5f},
770                                     {0.5f, 1.0f},
771                                     {1.0f, 0.5f},
772                                     {0.5f, 0.0f}};
773         int num_points = sizeof(points) / (2 * sizeof(float));
774
775         create_primitive_from_points(C, op, points, num_points, HD_AUTO);
776
777         return OPERATOR_FINISHED;
778 }
779
780 void MASK_OT_primitive_circle_add(wmOperatorType *ot)
781 {
782         /* identifiers */
783         ot->name = "Add Circle";
784         ot->description = "Add new circle-shaped spline";
785         ot->idname = "MASK_OT_primitive_circle_add";
786
787         /* api callbacks */
788         ot->exec = primitive_circle_add_exec;
789         ot->invoke = primitive_add_invoke;
790         ot->poll = ED_operator_mask;
791
792         /* flags */
793         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
794
795         /* properties */
796         define_prinitive_add_properties(ot);
797 }
798
799 /******************** primitive add suqare *********************/
800
801 static int primitive_square_add_exec(bContext *C, wmOperator *op)
802 {
803         const float points[4][2] = {{0.0f, 0.0f},
804                                     {0.0f, 1.0f},
805                                     {1.0f, 1.0f},
806                                     {1.0f, 0.0f}};
807         int num_points = sizeof(points) / (2 * sizeof(float));
808
809         create_primitive_from_points(C, op, points, num_points, HD_VECT);
810
811         return OPERATOR_FINISHED;
812 }
813
814 void MASK_OT_primitive_square_add(wmOperatorType *ot)
815 {
816         /* identifiers */
817         ot->name = "Add Square";
818         ot->description = "Add new square-shaped spline";
819         ot->idname = "MASK_OT_primitive_square_add";
820
821         /* api callbacks */
822         ot->exec = primitive_square_add_exec;
823         ot->invoke = primitive_add_invoke;
824         ot->poll = ED_operator_mask;
825
826         /* flags */
827         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
828
829         /* properties */
830         define_prinitive_add_properties(ot);
831 }