2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2012 Blender Foundation.
19 * All rights reserved.
22 * Contributor(s): Blender Foundation,
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/mask/mask_add.c
32 #include "MEM_guardedalloc.h"
36 #include "BKE_context.h"
37 #include "BKE_depsgraph.h"
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 */
48 #include "ED_mask.h" /* own include */
49 #include "ED_screen.h"
51 #include "RNA_access.h"
52 #include "RNA_define.h"
54 #include "mask_intern.h" /* own include */
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)
62 ScrArea *sa = CTX_wm_area(C);
63 ARegion *ar = CTX_wm_region(C);
65 MaskLayer *masklay, *point_masklay;
66 MaskSpline *point_spline;
67 MaskSplinePoint *point = NULL;
68 float dist = FLT_MAX, co[2];
73 ED_mask_get_size(sa, &width, &height);
74 ED_mask_pixelspace_factor(sa, ar, &scalex, &scaley);
76 co[0] = normal_co[0] * scalex;
77 co[1] = normal_co[1] * scaley;
79 for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
82 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
86 for (spline = masklay->splines.first; spline; spline = spline->next) {
88 MaskSplinePoint *cur_point;
90 for (i = 0, cur_point = use_deform ? spline->points_deform : spline->points;
91 i < spline->tot_point;
95 unsigned int tot_diff_point;
97 diff_points = BKE_mask_point_segment_diff(spline, cur_point, width, height,
102 unsigned int tot_feather_point;
103 float *feather_points = NULL, *points;
106 feather_points = BKE_mask_point_segment_feather_diff(spline, cur_point,
110 points = feather_points;
111 tot_point = tot_feather_point;
114 points = diff_points;
115 tot_point = tot_diff_point;
118 for (j = 0; j < tot_point - 1; j++) {
119 float cur_dist, a[2], b[2];
121 a[0] = points[2 * j] * scalex;
122 a[1] = points[2 * j + 1] * scaley;
124 b[0] = points[2 * j + 2] * scalex;
125 b[1] = points[2 * j + 3] * scaley;
127 cur_dist = dist_to_line_segment_v2(co, a, b);
129 if (cur_dist < dist) {
131 sub_v2_v2v2(tangent, &diff_points[2 * j + 2], &diff_points[2 * j]);
133 point_masklay = masklay;
134 point_spline = spline;
135 point = use_deform ? &spline->points[(cur_point - spline->points_deform)] : cur_point;
137 u = (float)j / tot_point;
143 MEM_freeN(feather_points);
145 MEM_freeN(diff_points);
151 if (point && dist < threshold) {
153 *masklay_r = point_masklay;
156 *spline_r = point_spline;
162 u = BKE_mask_spline_project_co(point_spline, point, u, normal_co, MASK_PROJ_ANY);
182 /******************** add vertex *********************/
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)
188 MaskSplinePoint *prev_point = NULL;
189 MaskSplinePoint *next_point = NULL;
193 copy_v2_v2(co, point_co);
196 /* point coordinate */
197 bezt = &new_point->bezt;
199 bezt->h1 = bezt->h2 = HD_ALIGN;
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
206 int point_index = reference_point - spline->points;
207 int delta = new_point == spline->points ? 1 : -1;
209 for (i = 0; i < spline->tot_point - 1; ++i) {
210 MaskSplinePoint *current_point;
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;
218 else if (point_index >= spline->tot_point) {
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);
235 bezt->h1 = bezt->h2 = MAX2(reference_point->bezt.h2, reference_point->bezt.h1);
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];
244 bezt->h1 = bezt->h2 = MAX2(prev_point->bezt.h2, next_point->bezt.h1);
246 /* note, we may want to copy other attributes later, radius? pressure? color? */
250 copy_v3_v3(bezt->vec[0], co);
251 copy_v3_v3(bezt->vec[1], co);
252 copy_v3_v3(bezt->vec[2], co);
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);
259 /* select new point */
260 MASKPOINT_SEL_ALL(new_point);
261 ED_mask_select_flush_all(mask);
265 /* **** add extrude vertex **** */
267 static void finSelectedSplinePoint(MaskLayer *masklay, MaskSpline **spline, MaskSplinePoint **point, short check_active)
269 MaskSpline *cur_spline = masklay->splines.first;
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;
286 for (i = 0; i < cur_spline->tot_point; i++) {
287 MaskSplinePoint *cur_point = &cur_spline->points[i];
289 if (MASKPOINT_ISSEL_ANY(cur_point)) {
290 if (*spline != NULL && *spline != cur_spline) {
299 *spline = cur_spline;
305 cur_spline = cur_spline->next;
309 /* **** add subdivide vertex **** */
311 static void mask_spline_add_point_at_index(MaskSpline *spline, int point_index)
313 MaskSplinePoint *new_point_array;
315 new_point_array = MEM_callocN(sizeof(MaskSplinePoint) * (spline->tot_point + 1), "add mask vert points");
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));
321 MEM_freeN(spline->points);
322 spline->points = new_point_array;
326 static int add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2])
330 MaskSplinePoint *point = NULL;
331 const float threshold = 9;
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;
339 ED_mask_select_toggle_all(mask, SEL_DESELECT);
341 mask_spline_add_point_at_index(spline, point_index);
343 new_point = &spline->points[point_index + 1];
345 setup_vertex_point(mask, spline, new_point, co, u, NULL, TRUE);
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);
350 masklay->act_spline = spline;
351 masklay->act_point = new_point;
353 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
361 static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2])
364 MaskSplinePoint *point;
365 MaskSplinePoint *new_point = NULL, *ref_point = NULL;
367 /* check on which side we want to add the point */
369 float tangent_point[2];
371 bool do_cyclic_correct = false;
372 bool do_prev; /* use prev point rather then next?? */
378 finSelectedSplinePoint(masklay, &spline, &point, TRUE);
381 ED_mask_select_toggle_all(mask, SEL_DESELECT);
383 point_index = (point - spline->points);
385 MASKPOINT_DESEL_ALL(point);
387 if ((spline->flag & MASK_SPLINE_CYCLIC) ||
388 (point_index > 0 && point_index != spline->tot_point - 1))
390 BKE_mask_calc_tangent_polyline(spline, point, tangent_point);
391 sub_v2_v2v2(tangent_co, co, point->bezt.vec[1]);
393 if (dot_v2v2(tangent_point, tangent_co) < 0.0f) {
400 else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == 0)) {
403 else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == spline->tot_point - 1)) {
407 do_prev = FALSE; /* quiet warning */
408 /* should never get here */
412 /* use the point before the active one */
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;
424 // print_v2("", tangent_point);
425 // printf("%d\n", point_index);
427 mask_spline_add_point_at_index(spline, point_index);
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));
436 ref_point = &spline->points[point_index];
437 new_point = &spline->points[point_index + 1];
440 masklay->act_point = new_point;
442 setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, FALSE);
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);
449 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
454 static int add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2])
457 MaskSplinePoint *point;
458 MaskSplinePoint *new_point = NULL, *ref_point = NULL;
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;
468 finSelectedSplinePoint(masklay, &spline, &point, TRUE);
471 ED_mask_select_toggle_all(mask, SEL_DESELECT);
474 /* no selected splines in active masklay, create new spline */
475 spline = BKE_mask_spline_add(masklay);
478 masklay->act_spline = spline;
479 new_point = spline->points;
481 masklay->act_point = new_point;
483 setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, FALSE);
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);
490 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
495 static int add_vertex_exec(bContext *C, wmOperator *op)
497 Scene *scene = CTX_data_scene(C);
498 Mask *mask = CTX_data_edit_mask(C);
504 /* if there's no active mask, create one */
505 mask = ED_mask_new(C, NULL);
508 masklay = BKE_mask_layer_active(mask);
510 if (masklay && masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
514 RNA_float_get_array(op->ptr, "location", co);
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)) {
519 /* cheap trick - double click for cyclic */
520 MaskSpline *spline = masklay->act_spline;
521 MaskSplinePoint *point = masklay->act_point;
523 const bool is_sta = (point == spline->points);
524 const bool is_end = (point == &spline->points[spline->tot_point - 1]);
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) {
530 return OPERATOR_CANCELLED;
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;
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);
541 /* TODO: only update this spline */
542 BKE_mask_update_display(mask, CFRA);
544 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
545 return OPERATOR_FINISHED;
549 if (!add_vertex_subdivide(C, mask, co)) {
550 if (!add_vertex_extrude(C, mask, masklay, co)) {
551 return OPERATOR_CANCELLED;
556 if (!add_vertex_subdivide(C, mask, co)) {
557 if (!add_vertex_new(C, mask, masklay, co)) {
558 return OPERATOR_CANCELLED;
563 /* TODO: only update this spline */
564 BKE_mask_update_display(mask, CFRA);
566 return OPERATOR_FINISHED;
569 static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
571 ScrArea *sa = CTX_wm_area(C);
572 ARegion *ar = CTX_wm_region(C);
576 ED_mask_mouse_pos(sa, ar, event->mval, co);
578 RNA_float_set_array(op->ptr, "location", co);
580 return add_vertex_exec(C, op);
583 void MASK_OT_add_vertex(wmOperatorType *ot)
586 ot->name = "Add Vertex";
587 ot->description = "Add vertex to active spline";
588 ot->idname = "MASK_OT_add_vertex";
591 ot->exec = add_vertex_exec;
592 ot->invoke = add_vertex_invoke;
593 ot->poll = ED_operator_mask;
596 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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);
603 /******************** add feather vertex *********************/
605 static int add_feather_vertex_exec(bContext *C, wmOperator *op)
607 Mask *mask = CTX_data_edit_mask(C);
610 MaskSplinePoint *point = NULL;
611 const float threshold = 9;
614 RNA_float_get_array(op->ptr, "location", co);
616 point = ED_mask_point_find_nearest(C, mask, co, threshold, NULL, NULL, NULL, NULL);
618 return OPERATOR_FINISHED;
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);
625 if (weight_scalar != 0.0f) {
626 w = w / weight_scalar;
629 BKE_mask_point_add_uw(point, u, w);
631 BKE_mask_update_display(mask, scene->r.cfra);
633 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
635 DAG_id_tag_update(&mask->id, 0);
637 return OPERATOR_FINISHED;
640 return OPERATOR_CANCELLED;
643 static int add_feather_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
645 ScrArea *sa = CTX_wm_area(C);
646 ARegion *ar = CTX_wm_region(C);
650 ED_mask_mouse_pos(sa, ar, event->mval, co);
652 RNA_float_set_array(op->ptr, "location", co);
654 return add_feather_vertex_exec(C, op);
657 void MASK_OT_add_feather_vertex(wmOperatorType *ot)
660 ot->name = "Add Feather Vertex";
661 ot->description = "Add vertex to feather";
662 ot->idname = "MASK_OT_add_feather_vertex";
665 ot->exec = add_feather_vertex_exec;
666 ot->invoke = add_feather_vertex_invoke;
667 ot->poll = ED_maskedit_mask_poll;
670 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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);
677 /******************** common primitive functions *********************/
679 static int create_primitive_from_points(bContext *C, wmOperator *op, const float (*points)[2],
680 int num_points, char handle_type)
682 ScrArea *sa = CTX_wm_area(C);
683 Scene *scene = CTX_data_scene(C);
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");
691 ED_mask_get_size(sa, &width, &height);
692 scale = (float)size / max_ii(width, height);
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);
702 /* Make it so new primitive is centered to mouse location. */
703 location[0] -= 0.5f * scale;
704 location[1] -= 0.5f * scale;
706 mask_layer = ED_mask_layer_ensure(C);
707 mask = CTX_data_edit_mask(C);
709 ED_mask_select_toggle_all(mask, SEL_DESELECT);
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);
717 mask_layer->act_spline = new_spline;
718 mask_layer->act_point = NULL;
720 for (i = 0; i < num_points; i++) {
721 MaskSplinePoint *new_point = &new_spline->points[i];
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);
727 new_point->bezt.h1 = handle_type;
728 new_point->bezt.h2 = handle_type;
729 BKE_mask_point_select_set(new_point, true);
732 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
734 /* TODO: only update this spline */
735 BKE_mask_update_display(mask, CFRA);
737 return OPERATOR_FINISHED;
740 static int primitive_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
742 ScrArea *sa = CTX_wm_area(C);
746 ED_mask_get_size(sa, &width, &height);
747 ED_mask_cursor_location_get(sa, cursor);
752 RNA_float_set_array(op->ptr, "location", cursor);
754 return op->type->exec(C, op);
757 static void define_prinitive_add_properties(wmOperatorType *ot)
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);
765 /******************** primitive add circle *********************/
767 static int primitive_circle_add_exec(bContext *C, wmOperator *op)
769 const float points[4][2] = {{0.0f, 0.5f},
773 int num_points = sizeof(points) / (2 * sizeof(float));
775 create_primitive_from_points(C, op, points, num_points, HD_AUTO);
777 return OPERATOR_FINISHED;
780 void MASK_OT_primitive_circle_add(wmOperatorType *ot)
783 ot->name = "Add Circle";
784 ot->description = "Add new circle-shaped spline";
785 ot->idname = "MASK_OT_primitive_circle_add";
788 ot->exec = primitive_circle_add_exec;
789 ot->invoke = primitive_add_invoke;
790 ot->poll = ED_operator_mask;
793 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
796 define_prinitive_add_properties(ot);
799 /******************** primitive add suqare *********************/
801 static int primitive_square_add_exec(bContext *C, wmOperator *op)
803 const float points[4][2] = {{0.0f, 0.0f},
807 int num_points = sizeof(points) / (2 * sizeof(float));
809 create_primitive_from_points(C, op, points, num_points, HD_VECT);
811 return OPERATOR_FINISHED;
814 void MASK_OT_primitive_square_add(wmOperatorType *ot)
817 ot->name = "Add Square";
818 ot->description = "Add new square-shaped spline";
819 ot->idname = "MASK_OT_primitive_square_add";
822 ot->exec = primitive_square_add_exec;
823 ot->invoke = primitive_add_invoke;
824 ot->poll = ED_operator_mask;
827 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
830 define_prinitive_add_properties(ot);