Cycles / Sky Texture:
[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_with_resolution(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_with_resolution(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 tangent[2], const float u,
186                                MaskSplinePoint *reference_point, const short reference_adjacent,
187                                const float view_zoom)
188 {
189         MaskSplinePoint *prev_point = NULL;
190         MaskSplinePoint *next_point = NULL;
191         BezTriple *bezt;
192         float co[3];
193         const float len = 10.0; /* default length of handle in pixel space */
194
195         copy_v2_v2(co, point_co);
196         co[2] = 0.0f;
197
198         /* point coordinate */
199         bezt = &new_point->bezt;
200
201         bezt->h1 = bezt->h2 = HD_ALIGN;
202
203         if (reference_point) {
204                 bezt->h1 = bezt->h2 = MAX2(reference_point->bezt.h2, reference_point->bezt.h1);
205         }
206         else if (reference_adjacent) {
207                 if (spline->tot_point != 1) {
208                         int index = (int)(new_point - spline->points);
209                         prev_point = &spline->points[(index - 1) % spline->tot_point];
210                         next_point = &spline->points[(index + 1) % spline->tot_point];
211
212                         bezt->h1 = bezt->h2 = MAX2(prev_point->bezt.h2, next_point->bezt.h1);
213
214                         /* note, we may want to copy other attributes later, radius? pressure? color? */
215                 }
216         }
217
218         copy_v3_v3(bezt->vec[0], co);
219         copy_v3_v3(bezt->vec[1], co);
220         copy_v3_v3(bezt->vec[2], co);
221
222         /* initial offset for handles */
223         if (spline->tot_point == 1) {
224                 /* first point of splien is aligned horizontally */
225                 bezt->vec[0][0] -= len * view_zoom;
226                 bezt->vec[2][0] += len * view_zoom;
227         }
228         else if (tangent) {
229                 float vec[2];
230
231                 copy_v2_v2(vec, tangent);
232
233                 mul_v2_fl(vec, len);
234
235                 sub_v2_v2(bezt->vec[0], vec);
236                 add_v2_v2(bezt->vec[2], vec);
237
238                 if (reference_adjacent) {
239                         BKE_mask_calc_handle_adjacent_interp(spline, new_point, u);
240                 }
241         }
242         else {
243
244                 /* calculating auto handles works much nicer */
245 #if 0
246                 /* next points are aligning in the direction of previous/next point */
247                 MaskSplinePoint *point;
248                 float v1[2], v2[2], vec[2];
249                 float dir = 1.0f;
250
251                 if (new_point == spline->points) {
252                         point = new_point + 1;
253                         dir = -1.0f;
254                 }
255                 else
256                         point = new_point - 1;
257
258                 if (spline->tot_point < 3) {
259                         v1[0] = point->bezt.vec[1][0] * width;
260                         v1[1] = point->bezt.vec[1][1] * height;
261
262                         v2[0] = new_point->bezt.vec[1][0] * width;
263                         v2[1] = new_point->bezt.vec[1][1] * height;
264                 }
265                 else {
266                         if (new_point == spline->points) {
267                                 v1[0] = spline->points[1].bezt.vec[1][0] * width;
268                                 v1[1] = spline->points[1].bezt.vec[1][1] * height;
269
270                                 v2[0] = spline->points[spline->tot_point - 1].bezt.vec[1][0] * width;
271                                 v2[1] = spline->points[spline->tot_point - 1].bezt.vec[1][1] * height;
272                         }
273                         else {
274                                 v1[0] = spline->points[0].bezt.vec[1][0] * width;
275                                 v1[1] = spline->points[0].bezt.vec[1][1] * height;
276
277                                 v2[0] = spline->points[spline->tot_point - 2].bezt.vec[1][0] * width;
278                                 v2[1] = spline->points[spline->tot_point - 2].bezt.vec[1][1] * height;
279                         }
280                 }
281
282                 sub_v2_v2v2(vec, v1, v2);
283                 mul_v2_fl(vec, len * dir / len_v2(vec));
284
285                 vec[0] /= width;
286                 vec[1] /= height;
287
288                 add_v2_v2(bezt->vec[0], vec);
289                 sub_v2_v2(bezt->vec[2], vec);
290 #else
291                 BKE_mask_calc_handle_point_auto(spline, new_point, TRUE);
292                 BKE_mask_calc_handle_adjacent_interp(spline, new_point, u);
293
294 #endif
295         }
296
297         BKE_mask_parent_init(&new_point->parent);
298
299         /* select new point */
300         MASKPOINT_SEL_ALL(new_point);
301         ED_mask_select_flush_all(mask);
302 }
303
304
305 /* **** add extrude vertex **** */
306
307 static void finSelectedSplinePoint(MaskLayer *masklay, MaskSpline **spline, MaskSplinePoint **point, short check_active)
308 {
309         MaskSpline *cur_spline = masklay->splines.first;
310
311         *spline = NULL;
312         *point = NULL;
313
314         if (check_active) {
315                 /* TODO, having an active point but no active spline is possible, why? */
316                 if (masklay->act_spline && masklay->act_point && MASKPOINT_ISSEL_ANY(masklay->act_point)) {
317                         *spline = masklay->act_spline;
318                         *point = masklay->act_point;
319                         return;
320                 }
321         }
322
323         while (cur_spline) {
324                 int i;
325
326                 for (i = 0; i < cur_spline->tot_point; i++) {
327                         MaskSplinePoint *cur_point = &cur_spline->points[i];
328
329                         if (MASKPOINT_ISSEL_ANY(cur_point)) {
330                                 if (*spline != NULL && *spline != cur_spline) {
331                                         *spline = NULL;
332                                         *point = NULL;
333                                         return;
334                                 }
335                                 else if (*point) {
336                                         *point = NULL;
337                                 }
338                                 else {
339                                         *spline = cur_spline;
340                                         *point = cur_point;
341                                 }
342                         }
343                 }
344
345                 cur_spline = cur_spline->next;
346         }
347 }
348
349 /* **** add subdivide vertex **** */
350
351 static void mask_spline_add_point_at_index(MaskSpline *spline, int point_index)
352 {
353         MaskSplinePoint *new_point_array;
354
355         new_point_array = MEM_callocN(sizeof(MaskSplinePoint) * (spline->tot_point + 1), "add mask vert points");
356
357         memcpy(new_point_array, spline->points, sizeof(MaskSplinePoint) * (point_index + 1));
358         memcpy(new_point_array + point_index + 2, spline->points + point_index + 1,
359                sizeof(MaskSplinePoint) * (spline->tot_point - point_index - 1));
360
361         MEM_freeN(spline->points);
362         spline->points = new_point_array;
363         spline->tot_point++;
364 }
365
366 static int add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2])
367 {
368         MaskLayer *masklay;
369         MaskSpline *spline;
370         MaskSplinePoint *point = NULL;
371         const float threshold = 9;
372         float tangent[2];
373         float u;
374
375         if (find_nearest_diff_point(C, mask, co, threshold, FALSE, &masklay, &spline, &point, &u, tangent, TRUE)) {
376                 MaskSplinePoint *new_point;
377                 int point_index = point - spline->points;
378
379                 ED_mask_select_toggle_all(mask, SEL_DESELECT);
380
381                 mask_spline_add_point_at_index(spline, point_index);
382
383                 new_point = &spline->points[point_index + 1];
384
385                 setup_vertex_point(mask, spline, new_point, co, tangent, u, NULL, TRUE, 1.0f);
386
387                 /* TODO - we could pass the spline! */
388                 BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index + 1, TRUE, TRUE);
389
390                 masklay->act_spline = spline;
391                 masklay->act_point = new_point;
392
393                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
394
395                 return TRUE;
396         }
397
398         return FALSE;
399 }
400
401 static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2])
402 {
403         MaskSpline *spline;
404         MaskSplinePoint *point;
405         MaskSplinePoint *new_point = NULL, *ref_point = NULL;
406
407         /* check on which side we want to add the point */
408         int point_index;
409         float tangent_point[2];
410         float tangent_co[2];
411         int do_cyclic_correct = FALSE;
412         int do_recalc_src = FALSE;  /* when extruding from endpoints only */
413         int do_prev;                /* use prev point rather then next?? */
414
415         if (!masklay) {
416                 return FALSE;
417         }
418         else {
419                 finSelectedSplinePoint(masklay, &spline, &point, TRUE);
420         }
421
422         ED_mask_select_toggle_all(mask, SEL_DESELECT);
423
424         point_index = (point - spline->points);
425
426         MASKPOINT_DESEL_ALL(point);
427
428         if ((spline->flag & MASK_SPLINE_CYCLIC) ||
429             (point_index > 0 && point_index != spline->tot_point - 1))
430         {
431                 BKE_mask_calc_tangent_polyline(spline, point, tangent_point);
432                 sub_v2_v2v2(tangent_co, co, point->bezt.vec[1]);
433
434                 if (dot_v2v2(tangent_point, tangent_co) < 0.0f) {
435                         do_prev = TRUE;
436                 }
437                 else {
438                         do_prev = FALSE;
439                 }
440         }
441         else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == 0)) {
442                 do_prev = TRUE;
443                 do_recalc_src = TRUE;
444         }
445         else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == spline->tot_point - 1)) {
446                 do_prev = FALSE;
447                 do_recalc_src = TRUE;
448         }
449         else {
450                 do_prev = FALSE;  /* quiet warning */
451                 /* should never get here */
452                 BLI_assert(0);
453         }
454
455         /* use the point before the active one */
456         if (do_prev) {
457                 point_index--;
458                 if (point_index < 0) {
459                         point_index += spline->tot_point; /* wrap index */
460                         if ((spline->flag & MASK_SPLINE_CYCLIC) == 0) {
461                                 do_cyclic_correct = TRUE;
462                                 point_index = 0;
463                         }
464                 }
465         }
466
467 //              print_v2("", tangent_point);
468 //              printf("%d\n", point_index);
469
470         mask_spline_add_point_at_index(spline, point_index);
471
472         if (do_cyclic_correct) {
473                 ref_point = &spline->points[point_index + 1];
474                 new_point = &spline->points[point_index];
475                 *ref_point = *new_point;
476                 memset(new_point, 0, sizeof(*new_point));
477         }
478         else {
479                 ref_point = &spline->points[point_index];
480                 new_point = &spline->points[point_index + 1];
481         }
482
483         masklay->act_point = new_point;
484
485         setup_vertex_point(mask, spline, new_point, co, NULL, 0.5f, ref_point, FALSE, 1.0f);
486
487         if (masklay->splines_shapes.first) {
488                 point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
489                 BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index, TRUE, TRUE);
490         }
491
492         if (do_recalc_src) {
493                 /* TODO, update keyframes in time */
494                 BKE_mask_calc_handle_point_auto(spline, ref_point, FALSE);
495         }
496
497         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
498
499         return TRUE;
500 }
501
502 static int add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2])
503 {
504         MaskSpline *spline;
505         MaskSplinePoint *point;
506         MaskSplinePoint *new_point = NULL, *ref_point = NULL;
507         float view_zoom;
508
509         if (!masklay) {
510                 /* if there's no masklay currently operationg on, create new one */
511                 masklay = BKE_mask_layer_new(mask, "");
512                 mask->masklay_act = mask->masklay_tot - 1;
513                 spline = NULL;
514                 point = NULL;
515         }
516         else {
517                 finSelectedSplinePoint(masklay, &spline, &point, TRUE);
518         }
519
520         ED_mask_select_toggle_all(mask, SEL_DESELECT);
521
522         if (!spline) {
523                 /* no selected splines in active masklay, create new spline */
524                 spline = BKE_mask_spline_add(masklay);
525         }
526
527         masklay->act_spline = spline;
528         new_point = spline->points;
529
530         masklay->act_point = new_point;
531
532         {
533                 ScrArea *sa = CTX_wm_area(C);
534                 ARegion *ar = CTX_wm_region(C);
535
536                 float zoom_x, zoom_y;
537                 /* calc view zoom in a simplistic way */
538                 ED_mask_zoom(sa, ar, &zoom_x, &zoom_y);
539
540                 view_zoom = zoom_x + zoom_y / 2.0f;
541                 view_zoom = 1.0f / view_zoom;
542
543                 /* arbitrary but gives good results */
544                 view_zoom /= 500.0f;
545         }
546
547         setup_vertex_point(mask, spline, new_point, co, NULL, 0.5f, ref_point, FALSE, view_zoom);
548
549         {
550                 int point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
551                 BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index, TRUE, TRUE);
552         }
553
554         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
555
556         return TRUE;
557 }
558
559 static int add_vertex_exec(bContext *C, wmOperator *op)
560 {
561         Scene *scene = CTX_data_scene(C);
562         Mask *mask = CTX_data_edit_mask(C);
563         MaskLayer *masklay;
564
565         float co[2];
566
567         if (mask == NULL) {
568                 /* if there's no active mask, create one */
569                 mask = ED_mask_new(C, NULL);
570         }
571
572         masklay = BKE_mask_layer_active(mask);
573
574         if (masklay && masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
575                 masklay = NULL;
576         }
577
578         RNA_float_get_array(op->ptr, "location", co);
579
580         /* TODO, having an active point but no active spline is possible, why? */
581         if (masklay && masklay->act_spline && masklay->act_point && MASKPOINT_ISSEL_ANY(masklay->act_point)) {
582
583                 /* cheap trick - double click for cyclic */
584                 MaskSpline *spline = masklay->act_spline;
585                 MaskSplinePoint *point = masklay->act_point;
586
587                 int is_sta = (point == spline->points);
588                 int is_end = (point == &spline->points[spline->tot_point - 1]);
589
590                 /* then check are we overlapping the mouse */
591                 if ((is_sta || is_end) && equals_v2v2(co, point->bezt.vec[1])) {
592                         if (spline->flag & MASK_SPLINE_CYCLIC) {
593                                 /* nothing to do */
594                                 return OPERATOR_CANCELLED;
595                         }
596                         else {
597                                 /* recalc the connecting point as well to make a nice even curve */
598                                 MaskSplinePoint *point_other = is_end ? spline->points : &spline->points[spline->tot_point - 1];
599                                 spline->flag |= MASK_SPLINE_CYCLIC;
600
601                                 /* TODO, update keyframes in time */
602                                 BKE_mask_calc_handle_point_auto(spline, point, FALSE);
603                                 BKE_mask_calc_handle_point_auto(spline, point_other, FALSE);
604
605                                 /* TODO: only update this spline */
606                                 BKE_mask_update_display(mask, CFRA);
607
608                                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
609                                 return OPERATOR_FINISHED;
610                         }
611                 }
612
613                 if (!add_vertex_subdivide(C, mask, co)) {
614                         if (!add_vertex_extrude(C, mask, masklay, co)) {
615                                 return OPERATOR_CANCELLED;
616                         }
617                 }
618         }
619         else {
620                 if (!add_vertex_subdivide(C, mask, co)) {
621                         if (!add_vertex_new(C, mask, masklay, co)) {
622                                 return OPERATOR_CANCELLED;
623                         }
624                 }
625         }
626
627         /* TODO: only update this spline */
628         BKE_mask_update_display(mask, CFRA);
629
630         return OPERATOR_FINISHED;
631 }
632
633 static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
634 {
635         ScrArea *sa = CTX_wm_area(C);
636         ARegion *ar = CTX_wm_region(C);
637
638         float co[2];
639
640         ED_mask_mouse_pos(sa, ar, event->mval, co);
641
642         RNA_float_set_array(op->ptr, "location", co);
643
644         return add_vertex_exec(C, op);
645 }
646
647 void MASK_OT_add_vertex(wmOperatorType *ot)
648 {
649         /* identifiers */
650         ot->name = "Add Vertex";
651         ot->description = "Add vertex to active spline";
652         ot->idname = "MASK_OT_add_vertex";
653
654         /* api callbacks */
655         ot->exec = add_vertex_exec;
656         ot->invoke = add_vertex_invoke;
657         ot->poll = ED_operator_mask;
658
659         /* flags */
660         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
661
662         /* properties */
663         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
664                              "Location", "Location of vertex in normalized space", -1.0f, 1.0f);
665 }
666
667 /******************** add feather vertex *********************/
668
669 static int add_feather_vertex_exec(bContext *C, wmOperator *op)
670 {
671         Mask *mask = CTX_data_edit_mask(C);
672         MaskLayer *masklay;
673         MaskSpline *spline;
674         MaskSplinePoint *point = NULL;
675         const float threshold = 9;
676         float co[2], u;
677
678         RNA_float_get_array(op->ptr, "location", co);
679
680         point = ED_mask_point_find_nearest(C, mask, co, threshold, NULL, NULL, NULL, NULL);
681         if (point)
682                 return OPERATOR_FINISHED;
683
684         if (find_nearest_diff_point(C, mask, co, threshold, TRUE, &masklay, &spline, &point, &u, NULL, TRUE)) {
685                 Scene *scene = CTX_data_scene(C);
686                 float w = BKE_mask_point_weight(spline, point, u);
687                 float weight_scalar = BKE_mask_point_weight_scalar(spline, point, u);
688
689                 if (weight_scalar != 0.0f) {
690                         w = w / weight_scalar;
691                 }
692
693                 BKE_mask_point_add_uw(point, u, w);
694
695                 BKE_mask_update_display(mask, scene->r.cfra);
696
697                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
698
699                 DAG_id_tag_update(&mask->id, 0);
700
701                 return OPERATOR_FINISHED;
702         }
703
704         return OPERATOR_CANCELLED;
705 }
706
707 static int add_feather_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
708 {
709         ScrArea *sa = CTX_wm_area(C);
710         ARegion *ar = CTX_wm_region(C);
711
712         float co[2];
713
714         ED_mask_mouse_pos(sa, ar, event->mval, co);
715
716         RNA_float_set_array(op->ptr, "location", co);
717
718         return add_feather_vertex_exec(C, op);
719 }
720
721 void MASK_OT_add_feather_vertex(wmOperatorType *ot)
722 {
723         /* identifiers */
724         ot->name = "Add Feather Vertex";
725         ot->description = "Add vertex to feather";
726         ot->idname = "MASK_OT_add_feather_vertex";
727
728         /* api callbacks */
729         ot->exec = add_feather_vertex_exec;
730         ot->invoke = add_feather_vertex_invoke;
731         ot->poll = ED_maskedit_mask_poll;
732
733         /* flags */
734         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
735
736         /* properties */
737         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
738                              "Location", "Location of vertex in normalized space", -1.0f, 1.0f);
739 }
740
741 /******************** common primitive functions *********************/
742
743 static int create_primitive_from_points(bContext *C, wmOperator *op, const float (*points)[2],
744                                         int num_points, char handle_type)
745 {
746         ScrArea *sa = CTX_wm_area(C);
747         Scene *scene = CTX_data_scene(C);
748         Mask *mask;
749         MaskLayer *mask_layer;
750         MaskSpline *new_spline;
751         float scale, location[2], frame_size[2];
752         int i, width, height;
753         int size = RNA_float_get(op->ptr, "size");
754
755         ED_mask_get_size(sa, &width, &height);
756         scale = (float)size / max_ii(width, height);
757
758         /* Get location in mask space. */
759         frame_size[0] = width;
760         frame_size[1] = height;
761         RNA_float_get_array(op->ptr, "location", location);
762         location[0] /= width;
763         location[1] /= height;
764         BKE_mask_coord_from_frame(location, location, frame_size);
765
766         /* Make it so new primitive is centered to mouse location. */
767         location[0] -= 0.5f * scale;
768         location[1] -= 0.5f * scale;
769
770         mask_layer = ED_mask_layer_ensure(C);
771         mask = CTX_data_edit_mask(C);
772
773         ED_mask_select_toggle_all(mask, SEL_DESELECT);
774
775         new_spline = BKE_mask_spline_add(mask_layer);
776         new_spline->flag = MASK_SPLINE_CYCLIC | SELECT;
777         new_spline->tot_point = num_points;
778         new_spline->points = MEM_recallocN(new_spline->points,
779                                            sizeof(MaskSplinePoint) * new_spline->tot_point);
780
781         mask_layer->act_spline = new_spline;
782         mask_layer->act_point = NULL;
783
784         for (i = 0; i < num_points; i++) {
785                 MaskSplinePoint *new_point = &new_spline->points[i];
786
787                 copy_v2_v2(new_point->bezt.vec[1], points[i]);
788                 mul_v2_fl(new_point->bezt.vec[1], scale);
789                 add_v2_v2(new_point->bezt.vec[1], location);
790
791                 new_point->bezt.h1 = handle_type;
792                 new_point->bezt.h2 = handle_type;
793                 BKE_mask_point_select_set(new_point, true);
794         }
795
796         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
797
798         /* TODO: only update this spline */
799         BKE_mask_update_display(mask, CFRA);
800
801         return OPERATOR_FINISHED;
802 }
803
804 static int primitive_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
805 {
806         ScrArea *sa = CTX_wm_area(C);
807         float cursor[2];
808         int width, height;
809
810         ED_mask_get_size(sa, &width, &height);
811         ED_mask_cursor_location_get(sa, cursor);
812
813         cursor[0] *= width;
814         cursor[1] *= height;
815
816         RNA_float_set_array(op->ptr, "location", cursor);
817
818         return op->type->exec(C, op);
819 }
820
821 static void define_prinitive_add_properties(wmOperatorType *ot)
822 {
823         RNA_def_float(ot->srna, "size", 100, -FLT_MAX, FLT_MAX,
824                              "Size", "Size of new circle", -FLT_MAX, FLT_MAX);
825         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
826                              "Location", "Location of new circle", -FLT_MAX, FLT_MAX);
827 }
828
829 /******************** primitive add circle *********************/
830
831 static int primitive_circle_add_exec(bContext *C, wmOperator *op)
832 {
833         const float points[4][2] = {{0.0f, 0.5f},
834                                     {0.5f, 1.0f},
835                                     {1.0f, 0.5f},
836                                     {0.5f, 0.0f}};
837         int num_points = sizeof(points) / (2 * sizeof(float));
838
839         create_primitive_from_points(C, op, points, num_points, HD_AUTO);
840
841         return OPERATOR_FINISHED;
842 }
843
844 void MASK_OT_primitive_circle_add(wmOperatorType *ot)
845 {
846         /* identifiers */
847         ot->name = "Add Circle";
848         ot->description = "Add new circle-shaped spline";
849         ot->idname = "MASK_OT_primitive_circle_add";
850
851         /* api callbacks */
852         ot->exec = primitive_circle_add_exec;
853         ot->invoke = primitive_add_invoke;
854         ot->poll = ED_operator_mask;
855
856         /* flags */
857         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
858
859         /* properties */
860         define_prinitive_add_properties(ot);
861 }
862
863 /******************** primitive add suqare *********************/
864
865 static int primitive_square_add_exec(bContext *C, wmOperator *op)
866 {
867         const float points[4][2] = {{0.0f, 0.0f},
868                                     {0.0f, 1.0f},
869                                     {1.0f, 1.0f},
870                                     {1.0f, 0.0f}};
871         int num_points = sizeof(points) / (2 * sizeof(float));
872
873         create_primitive_from_points(C, op, points, num_points, HD_VECT);
874
875         return OPERATOR_FINISHED;
876 }
877
878 void MASK_OT_primitive_square_add(wmOperatorType *ot)
879 {
880         /* identifiers */
881         ot->name = "Add Square";
882         ot->description = "Add new square-shaped spline";
883         ot->idname = "MASK_OT_primitive_square_add";
884
885         /* api callbacks */
886         ot->exec = primitive_square_add_exec;
887         ot->invoke = primitive_add_invoke;
888         ot->poll = ED_operator_mask;
889
890         /* flags */
891         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
892
893         /* properties */
894         define_prinitive_add_properties(ot);
895 }