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