Blender V4.3
mask_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2012 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
11#include "BLI_listbase.h"
12#include "BLI_math_matrix.h"
13#include "BLI_math_vector.h"
14
15#include "BKE_context.hh"
16#include "BKE_mask.h"
17
18#include "BLT_translation.hh"
19
20#include "DEG_depsgraph.hh"
22
23#include "DNA_mask_types.h"
24#include "DNA_object_types.h" /* SELECT */
25#include "DNA_scene_types.h"
26
27#include "WM_api.hh"
28#include "WM_types.hh"
29
30#include "ED_clip.hh"
31#include "ED_image.hh"
32#include "ED_mask.hh"
33#include "ED_select_utils.hh"
34
35#include "ANIM_keyframing.hh"
36
37#include "UI_interface_icons.hh"
38
39#include "RNA_access.hh"
40#include "RNA_define.hh"
41
42#include "mask_intern.hh" /* own include */
43
44/******************** create new mask *********************/
45
46Mask *ED_mask_new(bContext *C, const char *name)
47{
48 ScrArea *area = CTX_wm_area(C);
49 Main *bmain = CTX_data_main(C);
50 Mask *mask;
51
52 mask = BKE_mask_new(bmain, name);
53
54 if (area && area->spacedata.first) {
55 switch (area->spacetype) {
56 case SPACE_CLIP: {
57 SpaceClip *sc = static_cast<SpaceClip *>(area->spacedata.first);
58 ED_space_clip_set_mask(C, sc, mask);
59 break;
60 }
61 case SPACE_SEQ: {
62 /* do nothing */
63 break;
64 }
65 case SPACE_IMAGE: {
66 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
67 ED_space_image_set_mask(C, sima, mask);
68 break;
69 }
70 }
71 }
72
73 return mask;
74}
75
76MaskLayer *ED_mask_layer_ensure(bContext *C, bool *r_added_mask)
77{
78 Mask *mask = CTX_data_edit_mask(C);
79 MaskLayer *mask_layer;
80
81 if (mask == nullptr) {
82 /* If there's no active mask, create one. */
83 mask = ED_mask_new(C, nullptr);
84 *r_added_mask = true;
85 }
86
87 mask_layer = BKE_mask_layer_active(mask);
88 if (mask_layer == nullptr) {
89 /* If there's no active mask layer, create one. */
90 mask_layer = BKE_mask_layer_new(mask, "");
91 }
92
93 return mask_layer;
94}
95
97{
98 char name[MAX_ID_NAME - 2];
99
100 RNA_string_get(op->ptr, "name", name);
101
102 ED_mask_new(C, name);
103
105
106 return OPERATOR_FINISHED;
107}
108
110{
111 /* identifiers */
112 ot->name = "New Mask";
113 ot->description = "Create new mask";
114 ot->idname = "MASK_OT_new";
115
116 /* flags */
118
119 /* api callbacks */
122
123 /* properties */
124 RNA_def_string(ot->srna, "name", nullptr, MAX_ID_NAME - 2, "Name", "Name of new mask");
125}
126
127/******************** create new mask layer *********************/
128
130{
131 Mask *mask = CTX_data_edit_mask(C);
132 char name[MAX_ID_NAME - 2];
133
134 RNA_string_get(op->ptr, "name", name);
135
136 BKE_mask_layer_new(mask, name);
137 mask->masklay_act = mask->masklay_tot - 1;
138
141
142 return OPERATOR_FINISHED;
143}
144
146{
147 /* identifiers */
148 ot->name = "Add Mask Layer";
149 ot->description = "Add new mask layer for masking";
150 ot->idname = "MASK_OT_layer_new";
151
152 /* api callbacks */
155
156 /* flags */
158
159 /* properties */
160 RNA_def_string(ot->srna, "name", nullptr, MAX_ID_NAME - 2, "Name", "Name of new mask layer");
161}
162
163/******************** remove mask layer *********************/
164
166{
167 Mask *mask = CTX_data_edit_mask(C);
168 MaskLayer *mask_layer = BKE_mask_layer_active(mask);
169
170 if (mask_layer) {
171 BKE_mask_layer_remove(mask, mask_layer);
172
175 }
176
177 return OPERATOR_FINISHED;
178}
179
181{
182 /* identifiers */
183 ot->name = "Remove Mask Layer";
184 ot->description = "Remove mask layer";
185 ot->idname = "MASK_OT_layer_remove";
186
187 /* api callbacks */
190
191 /* flags */
193}
194
195/******************** slide *********************/
196
197enum {
203};
204
206 /* Generic fields. */
216
218
219 /* Previous clip coordinate which was resolved from mouse position (0, 0).
220 * Is used to compensate for view offset moving in-between of mouse events when
221 * lock-to-selection is enabled. */
223
224 float no[2];
225
227
229
230 /* Data needed to restore the state. */
231 float vec[3][3];
233
234 /* Point sliding. */
235
236 /* Handle sliding. */
238
239 /* Feather sliding. */
242};
243
244static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float co[2])
245{
246 BKE_mask_coord_to_movieclip(sc->clip, &sc->user, r_co, co);
247 ED_clip_point_undistorted_pos(sc, r_co, r_co);
248 BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co);
249}
250
251static bool spline_under_mouse_get(const bContext *C,
252 Mask *mask_orig,
253 const float co[2],
254 MaskLayer **r_mask_layer,
255 MaskSpline **r_mask_spline)
256{
257 const float threshold = 19.0f;
258 ScrArea *area = CTX_wm_area(C);
260 float closest_dist_squared = 0.0f;
261 MaskLayer *closest_layer = nullptr;
262 MaskSpline *closest_spline = nullptr;
263 bool undistort = false;
264 *r_mask_layer = nullptr;
265 *r_mask_spline = nullptr;
266
268 Mask *mask_eval = (Mask *)DEG_get_evaluated_id(depsgraph, &mask_orig->id);
269
270 int width, height;
271 ED_mask_get_size(area, &width, &height);
272 float pixel_co[2];
273 pixel_co[0] = co[0] * width;
274 pixel_co[1] = co[1] * height;
275 if (sc != nullptr) {
276 undistort = (sc->clip != nullptr) &&
278 }
279
280 for (MaskLayer *mask_layer_orig = static_cast<MaskLayer *>(mask_orig->masklayers.first),
281 *mask_layer_eval = static_cast<MaskLayer *>(mask_eval->masklayers.first);
282 mask_layer_orig != nullptr;
283 mask_layer_orig = mask_layer_orig->next, mask_layer_eval = mask_layer_eval->next)
284 {
285 if (mask_layer_orig->visibility_flag & (MASK_HIDE_VIEW | MASK_HIDE_SELECT)) {
286 continue;
287 }
288 for (MaskSpline *spline_orig = static_cast<MaskSpline *>(mask_layer_orig->splines.first),
289 *spline_eval = static_cast<MaskSpline *>(mask_layer_eval->splines.first);
290 spline_orig != nullptr;
291 spline_orig = spline_orig->next, spline_eval = spline_eval->next)
292 {
293 if ((spline_orig->flag & SELECT) == 0) {
294 continue;
295 }
296 MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline_eval);
297 float min[2], max[2], center[2];
298 INIT_MINMAX2(min, max);
299 for (int i = 0; i < spline_orig->tot_point; i++) {
300 MaskSplinePoint *point_deform = &points_array[i];
301 BezTriple *bezt = &point_deform->bezt;
302
303 float vert[2];
304
305 copy_v2_v2(vert, bezt->vec[1]);
306
307 if (undistort) {
308 mask_point_undistort_pos(sc, vert, vert);
309 }
310
311 minmax_v2v2_v2(min, max, vert);
312 }
313
314 center[0] = (min[0] + max[0]) / 2.0f * width;
315 center[1] = (min[1] + max[1]) / 2.0f * height;
316 float dist_squared = len_squared_v2v2(pixel_co, center);
317 float max_bb_side = min_ff((max[0] - min[0]) * width, (max[1] - min[1]) * height);
318 if (dist_squared <= max_bb_side * max_bb_side * 0.5f &&
319 (closest_spline == nullptr || dist_squared < closest_dist_squared))
320 {
321 closest_layer = mask_layer_orig;
322 closest_spline = spline_orig;
323 closest_dist_squared = dist_squared;
324 }
325 }
326 }
327 if (closest_dist_squared < square_f(threshold) && closest_spline != nullptr) {
328 float diff_score;
330 mask_orig,
331 co,
332 threshold,
333 false,
334 nullptr,
335 true,
336 false,
337 nullptr,
338 nullptr,
339 nullptr,
340 nullptr,
341 &diff_score))
342 {
343 if (square_f(diff_score) < closest_dist_squared) {
344 return false;
345 }
346 }
347
348 *r_mask_layer = closest_layer;
349 *r_mask_spline = closest_spline;
350 return true;
351 }
352 return false;
353}
354
356{
357 for (int i = 0; i < spline->tot_point; i++) {
358 MaskSplinePoint *point = &spline->points[i];
359
360 if (point->bezt.weight != 0.0f) {
361 return false;
362 }
363 }
364
365 return true;
366}
367
368static void select_sliding_point(Mask *mask,
369 MaskLayer *mask_layer,
370 MaskSpline *spline,
371 MaskSplinePoint *point,
372 eMaskWhichHandle which_handle)
373{
375
376 switch (which_handle) {
378 BKE_mask_point_select_set(point, true);
379 break;
381 point->bezt.f1 |= SELECT;
382 break;
384 point->bezt.f3 |= SELECT;
385 break;
387 point->bezt.f1 |= SELECT;
388 point->bezt.f3 |= SELECT;
389 break;
390 default:
391 BLI_assert_msg(0, "Unexpected situation in select_sliding_point()");
392 }
393
394 mask_layer->act_spline = spline;
395 mask_layer->act_point = point;
397}
398
400{
401 BezTriple *bezt = &point->bezt;
402
403 if (which_handle == MASK_WHICH_HANDLE_LEFT) {
404 if (bezt->h1 == HD_VECT) {
405 bezt->h1 = HD_FREE;
406 }
407 else if (bezt->h1 == HD_AUTO) {
408 bezt->h1 = HD_ALIGN_DOUBLESIDE;
409 bezt->h2 = HD_ALIGN_DOUBLESIDE;
410 }
411 }
412 else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
413 if (bezt->h2 == HD_VECT) {
414 bezt->h2 = HD_FREE;
415 }
416 else if (bezt->h2 == HD_AUTO) {
417 bezt->h1 = HD_ALIGN_DOUBLESIDE;
418 bezt->h2 = HD_ALIGN_DOUBLESIDE;
419 }
420 }
421}
422
424{
425 ScrArea *area = CTX_wm_area(C);
426 ARegion *region = CTX_wm_region(C);
427
428 Mask *mask = CTX_data_edit_mask(C);
429 SlidePointData *customdata = nullptr;
430 MaskLayer *mask_layer, *cv_mask_layer, *feather_mask_layer;
431 MaskSpline *spline, *cv_spline, *feather_spline;
432 MaskSplinePoint *point, *cv_point, *feather_point;
433 MaskSplinePointUW *uw = nullptr;
434 int width, height, action = SLIDE_ACTION_NONE;
435 const bool slide_feather = RNA_boolean_get(op->ptr, "slide_feather");
436 float co[2], cv_score, feather_score;
437 const float threshold = 19;
438 eMaskWhichHandle which_handle;
439
440 MaskViewLockState lock_state;
441 ED_mask_view_lock_state_store(C, &lock_state);
442
443 ED_mask_mouse_pos(area, region, event->mval, co);
444 ED_mask_get_size(area, &width, &height);
445
447 C, mask, co, threshold, &cv_mask_layer, &cv_spline, &which_handle, &cv_score);
448
450 mask,
451 co,
452 threshold,
453 &feather_mask_layer,
454 &feather_spline,
455 &feather_point,
456 &uw,
457 &feather_score))
458 {
459 if (slide_feather || !cv_point || feather_score < cv_score) {
460 action = SLIDE_ACTION_FEATHER;
461
462 mask_layer = feather_mask_layer;
463 spline = feather_spline;
464 point = feather_point;
465 }
466 }
467
468 if (cv_point && action == SLIDE_ACTION_NONE) {
469 if (which_handle != MASK_WHICH_HANDLE_NONE) {
470 action = SLIDE_ACTION_HANDLE;
471 }
472 else {
473 action = SLIDE_ACTION_POINT;
474 }
475
476 mask_layer = cv_mask_layer;
477 spline = cv_spline;
478 point = cv_point;
479 }
480
481 if (action == SLIDE_ACTION_NONE) {
482 if (spline_under_mouse_get(C, mask, co, &mask_layer, &spline)) {
483 action = SLIDE_ACTION_SPLINE;
484 point = nullptr;
485 }
486 }
487
488 if (action != SLIDE_ACTION_NONE) {
489 customdata = MEM_cnew<SlidePointData>("mask slide point data");
490 customdata->event_invoke_type = event->type;
491 customdata->mask = mask;
492 customdata->mask_layer = mask_layer;
493 customdata->spline = spline;
494 customdata->point = point;
495 customdata->width = width;
496 customdata->height = height;
497 customdata->action = action;
498 customdata->uw = uw;
499
500 customdata->is_sliding_new_point = RNA_boolean_get(op->ptr, "is_new_point");
501
502 if (customdata->action != SLIDE_ACTION_SPLINE) {
503 customdata->old_h1 = point->bezt.h1;
504 customdata->old_h2 = point->bezt.h2;
505 select_sliding_point(mask, mask_layer, spline, point, which_handle);
506 check_sliding_handle_type(point, which_handle);
507 }
508
509 if (uw) {
510 float co_uw[2];
511 float weight_scalar = BKE_mask_point_weight_scalar(spline, point, uw->u);
512
513 customdata->weight = uw->w;
514 customdata->weight_scalar = weight_scalar;
515 BKE_mask_point_segment_co(spline, point, uw->u, co_uw);
516 BKE_mask_point_normal(spline, point, uw->u, customdata->no);
517
518 madd_v2_v2v2fl(customdata->prev_feather_coord, co_uw, customdata->no, uw->w * weight_scalar);
519 }
520 else if (customdata->action != SLIDE_ACTION_SPLINE) {
521 BezTriple *bezt = &point->bezt;
522
523 customdata->weight = bezt->weight;
524 customdata->weight_scalar = 1.0f;
525 BKE_mask_point_normal(spline, point, 0.0f, customdata->no);
526
527 madd_v2_v2v2fl(customdata->prev_feather_coord, bezt->vec[1], customdata->no, bezt->weight);
528 }
529
530 if (customdata->action == SLIDE_ACTION_FEATHER) {
532 }
533
534 if (customdata->action != SLIDE_ACTION_SPLINE) {
535 copy_m3_m3(customdata->vec, point->bezt.vec);
536 if (which_handle != MASK_WHICH_HANDLE_NONE) {
537 BKE_mask_point_handle(point, which_handle, customdata->orig_handle_coord);
538 copy_v2_v2(customdata->prev_handle_coord, customdata->orig_handle_coord);
539 }
540 }
541 customdata->which_handle = which_handle;
542
543 {
545 DEG_id_tag_update(&mask->id, 0);
546
548 }
549
550 ED_mask_mouse_pos(area, region, event->mval, customdata->prev_mouse_coord);
551
552 const int zero_mouse[2] = {0, 0};
553 ED_mask_mouse_pos(area, region, zero_mouse, customdata->prev_zero_coord);
554 }
555
556 return customdata;
557}
558
559static int slide_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
560{
561 Mask *mask = CTX_data_edit_mask(C);
562 SlidePointData *slidedata;
563
564 if (mask == nullptr) {
566 }
567
568 slidedata = slide_point_customdata(C, op, event);
569
570 if (slidedata) {
571 op->customdata = slidedata;
572
574
575 slidedata->mask_layer->act_spline = slidedata->spline;
576 slidedata->mask_layer->act_point = slidedata->point;
577
579
581 }
582
584}
585
586static void slide_point_delta_all_feather(SlidePointData *data, float delta)
587{
588 for (int i = 0; i < data->spline->tot_point; i++) {
589 MaskSplinePoint *point = &data->spline->points[i];
590 MaskSplinePoint *orig_point = &data->orig_spline->points[i];
591
592 point->bezt.weight = orig_point->bezt.weight + delta;
593 if (point->bezt.weight < 0.0f) {
594 point->bezt.weight = 0.0f;
595 }
596 }
597}
598
600{
601 for (int i = 0; i < data->spline->tot_point; i++) {
602 MaskSplinePoint *point = &data->spline->points[i];
603 MaskSplinePoint *orig_point = &data->orig_spline->points[i];
604
605 point->bezt = orig_point->bezt;
606
607 for (int j = 0; j < point->tot_uw; j++) {
608 point->uw[j] = orig_point->uw[j];
609 }
610 }
611}
612
614{
615 /* cancel sliding */
616
617 if (data->orig_spline) {
619 }
620 else {
621 if (data->action == SLIDE_ACTION_FEATHER) {
622 if (data->uw) {
623 data->uw->w = data->weight;
624 }
625 else {
626 data->point->bezt.weight = data->weight;
627 }
628 }
629 else if (data->action != SLIDE_ACTION_SPLINE) {
630 copy_m3_m3(data->point->bezt.vec, data->vec);
631 data->point->bezt.h1 = data->old_h1;
632 data->point->bezt.h2 = data->old_h2;
633 }
634 }
635}
636
638{
639 if (data->orig_spline) {
640 BKE_mask_spline_free(data->orig_spline);
641 }
642
643 MEM_freeN(data);
644}
645
646static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
647{
649 BezTriple *bezt = &data->point->bezt;
650 float co[2];
651
652 switch (event->type) {
653 case EVT_LEFTALTKEY:
654 case EVT_RIGHTALTKEY:
655 case EVT_LEFTSHIFTKEY:
657 if (ELEM(event->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY)) {
658 if (data->action == SLIDE_ACTION_FEATHER) {
659 data->is_overall_feather = (event->val == KM_PRESS);
660 }
661 else {
662 data->is_curvature_only = (event->val == KM_PRESS);
663 }
664 }
665
667 data->is_accurate = (event->val == KM_PRESS);
668 }
669
670 ATTR_FALLTHROUGH; /* update CV position */
671 case MOUSEMOVE: {
672 ScrArea *area = CTX_wm_area(C);
673 ARegion *region = CTX_wm_region(C);
674 float delta[2];
675
676 ED_mask_mouse_pos(area, region, event->mval, co);
677 sub_v2_v2v2(delta, co, data->prev_mouse_coord);
678 copy_v2_v2(data->prev_mouse_coord, co);
679
680 /* Compensate for possibly moved view offset since the last event.
681 * The idea is to see how mapping of a fixed and known position did change. */
682 {
683 const int zero_mouse[2] = {0, 0};
684 float zero_coord[2];
685 ED_mask_mouse_pos(area, region, zero_mouse, zero_coord);
686
687 float zero_delta[2];
688 sub_v2_v2v2(zero_delta, zero_coord, data->prev_zero_coord);
689 sub_v2_v2(delta, zero_delta);
690
691 copy_v2_v2(data->prev_zero_coord, zero_coord);
692 }
693
694 if (data->is_accurate) {
695 mul_v2_fl(delta, 0.2f);
696 }
697
698 if (data->action == SLIDE_ACTION_HANDLE) {
699 float new_handle[2];
700
701 if (data->is_sliding_new_point && data->which_handle == MASK_WHICH_HANDLE_STICK) {
702 if (ELEM(data->point,
703 &data->spline->points[0],
704 &data->spline->points[data->spline->tot_point - 1]))
705 {
706 std::swap(delta[0], delta[1]);
707 delta[1] *= -1;
708
709 /* flip last point */
710 if (data->point != &data->spline->points[0]) {
711 negate_v2(delta);
712 }
713 }
714 }
715
716 add_v2_v2v2(new_handle, data->prev_handle_coord, delta);
717
718 BKE_mask_point_set_handle(data->point,
719 data->which_handle,
720 new_handle,
721 data->is_curvature_only,
722 data->orig_handle_coord,
723 data->vec);
724 BKE_mask_point_handle(data->point, data->which_handle, data->prev_handle_coord);
725
726 if (data->is_sliding_new_point) {
727 if (ELEM(data->which_handle, MASK_WHICH_HANDLE_LEFT, MASK_WHICH_HANDLE_RIGHT)) {
728 float vec[2];
729 short self_handle = (data->which_handle == MASK_WHICH_HANDLE_LEFT) ? 0 : 2;
730 short other_handle = (data->which_handle == MASK_WHICH_HANDLE_LEFT) ? 2 : 0;
731
732 sub_v2_v2v2(vec, bezt->vec[1], bezt->vec[self_handle]);
733 add_v2_v2v2(bezt->vec[other_handle], bezt->vec[1], vec);
734 }
735 }
736 }
737 else if (data->action == SLIDE_ACTION_POINT) {
738 add_v2_v2(bezt->vec[0], delta);
739 add_v2_v2(bezt->vec[1], delta);
740 add_v2_v2(bezt->vec[2], delta);
741 }
742 else if (data->action == SLIDE_ACTION_FEATHER) {
743 float vec[2], no[2], p[2], c[2], w, offco[2];
744 float *weight = nullptr;
745 float weight_scalar = 1.0f;
746 bool is_overall_feather = data->is_overall_feather || data->is_initial_feather;
747
748 add_v2_v2v2(offco, data->prev_feather_coord, delta);
749
750 if (data->uw) {
751 /* project on both sides and find the closest one,
752 * prevents flickering when projecting onto both sides can happen */
753 const float u_pos = BKE_mask_spline_project_co(
754 data->spline, data->point, data->uw->u, offco, MASK_PROJ_NEG);
755 const float u_neg = BKE_mask_spline_project_co(
756 data->spline, data->point, data->uw->u, offco, MASK_PROJ_POS);
757 float dist_pos = FLT_MAX;
758 float dist_neg = FLT_MAX;
759 float co_pos[2];
760 float co_neg[2];
761 float u;
762
763 if (u_pos > 0.0f && u_pos < 1.0f) {
764 BKE_mask_point_segment_co(data->spline, data->point, u_pos, co_pos);
765 dist_pos = len_squared_v2v2(offco, co_pos);
766 }
767
768 if (u_neg > 0.0f && u_neg < 1.0f) {
769 BKE_mask_point_segment_co(data->spline, data->point, u_neg, co_neg);
770 dist_neg = len_squared_v2v2(offco, co_neg);
771 }
772
773 u = dist_pos < dist_neg ? u_pos : u_neg;
774
775 if (u > 0.0f && u < 1.0f) {
776 data->uw->u = u;
777
778 data->uw = BKE_mask_point_sort_uw(data->point, data->uw);
779 weight = &data->uw->w;
780 weight_scalar = BKE_mask_point_weight_scalar(data->spline, data->point, u);
781 if (weight_scalar != 0.0f) {
782 weight_scalar = 1.0f / weight_scalar;
783 }
784
785 BKE_mask_point_normal(data->spline, data->point, data->uw->u, no);
786 BKE_mask_point_segment_co(data->spline, data->point, data->uw->u, p);
787 }
788 }
789 else {
790 weight = &bezt->weight;
791 /* weight_scalar = 1.0f; keep as is */
792 copy_v2_v2(no, data->no);
793 copy_v2_v2(p, bezt->vec[1]);
794 }
795
796 if (weight) {
797 sub_v2_v2v2(c, offco, p);
798 project_v2_v2v2_normalized(vec, c, no);
799
800 w = len_v2(vec);
801
802 if (is_overall_feather) {
803 float w_delta;
804
805 if (dot_v2v2(no, vec) <= 0.0f) {
806 w = -w;
807 }
808
809 w_delta = w - data->weight * data->weight_scalar;
810
811 if (data->orig_spline == nullptr) {
812 /* restore weight for currently sliding point, so orig_spline would be created
813 * with original weights used
814 */
815 *weight = data->weight;
816
817 data->orig_spline = BKE_mask_spline_copy(data->spline);
818 }
819
820 if (data->is_initial_feather) {
821 *weight = w * weight_scalar;
822 }
823
824 slide_point_delta_all_feather(data, w_delta);
825 }
826 else {
827 if (dot_v2v2(no, vec) <= 0.0f) {
828 w = 0.0f;
829 }
830
831 if (data->orig_spline) {
832 /* restore possible overall feather changes */
834
835 BKE_mask_spline_free(data->orig_spline);
836 data->orig_spline = nullptr;
837 }
838
839 if (weight_scalar != 0.0f) {
840 *weight = w * weight_scalar;
841 }
842 }
843
844 copy_v2_v2(data->prev_feather_coord, offco);
845 }
846 }
847 else if (data->action == SLIDE_ACTION_SPLINE) {
848 if (data->orig_spline == nullptr) {
849 data->orig_spline = BKE_mask_spline_copy(data->spline);
850 }
851
852 for (int i = 0; i < data->spline->tot_point; i++) {
853 MaskSplinePoint *point = &data->spline->points[i];
854 add_v2_v2(point->bezt.vec[0], delta);
855 add_v2_v2(point->bezt.vec[1], delta);
856 add_v2_v2(point->bezt.vec[2], delta);
857 }
858 }
859
860 WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
861 DEG_id_tag_update(&data->mask->id, 0);
862
863 break;
864 }
865
866 case LEFTMOUSE:
867 case RIGHTMOUSE:
868 if (event->type == data->event_invoke_type && event->val == KM_RELEASE) {
869 Scene *scene = CTX_data_scene(C);
870
871 /* Don't key sliding feather UW's. */
872 if ((data->action == SLIDE_ACTION_FEATHER && data->uw) == false) {
874 ED_mask_layer_shape_auto_key(data->mask_layer, scene->r.cfra);
875 }
876 }
877
878 if (data->is_sliding_new_point) {
879 if (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) < FLT_EPSILON) {
880 bezt->h1 = HD_VECT;
881 }
882 if (len_squared_v2v2(bezt->vec[2], bezt->vec[1]) < FLT_EPSILON) {
883 bezt->h2 = HD_VECT;
884 }
885 }
886
887 WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
888 DEG_id_tag_update(&data->mask->id, 0);
889
890 free_slide_point_data(data); /* keep this last! */
891 return OPERATOR_FINISHED;
892 }
893 else if (event->type != data->event_invoke_type && event->val == KM_PRESS) {
894 /* pass to ESCKEY */
896 }
897 else {
898 break;
899 }
900
901 case EVT_ESCKEY:
902 cancel_slide_point(data);
903
904 WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
905 DEG_id_tag_update(&data->mask->id, 0);
906
907 free_slide_point_data(data); /* keep this last! */
908 return OPERATOR_CANCELLED;
909 }
910
912}
913
915{
916 PropertyRNA *prop;
917
918 /* identifiers */
919 ot->name = "Slide Point";
920 ot->description = "Slide control points";
921 ot->idname = "MASK_OT_slide_point";
922
923 /* api callbacks */
927
928 /* flags */
930
932 "slide_feather",
933 false,
934 "Slide Feather",
935 "First try to slide feather instead of vertex");
936
937 prop = RNA_def_boolean(
938 ot->srna, "is_new_point", false, "Slide New Point", "Newly created vertex is being slid");
940}
941
942/******************** slide spline curvature *********************/
943
962
964{
965 *slide_data->adjust_bezt = slide_data->bezt_backup;
966 *slide_data->other_bezt = slide_data->other_bezt_backup;
967}
968
970{
971 MEM_freeN(slide_data);
972}
973
974static bool slide_spline_curvature_check(bContext *C, const wmEvent *event)
975{
976 Mask *mask = CTX_data_edit_mask(C);
977 float co[2];
978 const float threshold = 19.0f;
979
981
982 if (ED_mask_point_find_nearest(C, mask, co, threshold, nullptr, nullptr, nullptr, nullptr)) {
983 return false;
984 }
985
987 C, mask, co, threshold, nullptr, nullptr, nullptr, nullptr, nullptr))
988 {
989 return false;
990 }
991
992 return true;
993}
994
996 const wmEvent *event)
997{
998 const float threshold = 19.0f;
999
1000 Mask *mask = CTX_data_edit_mask(C);
1001 SlideSplineCurvatureData *slide_data;
1002 MaskLayer *mask_layer;
1003 MaskSpline *spline;
1005 float u, co[2];
1006 BezTriple *next_bezt;
1007
1008 MaskViewLockState lock_state;
1009 ED_mask_view_lock_state_store(C, &lock_state);
1010
1011 ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, co);
1012
1014 mask,
1015 co,
1016 threshold,
1017 false,
1018 nullptr,
1019 true,
1020 false,
1021 &mask_layer,
1022 &spline,
1023 &point,
1024 &u,
1025 nullptr))
1026 {
1027 return nullptr;
1028 }
1029
1030 next_bezt = BKE_mask_spline_point_next_bezt(spline, spline->points, point);
1031 if (next_bezt == nullptr) {
1032 return nullptr;
1033 }
1034
1035 slide_data = MEM_cnew<SlideSplineCurvatureData>("slide curvature slide");
1036 slide_data->event_invoke_type = event->type;
1037 slide_data->mask = mask;
1038 slide_data->mask_layer = mask_layer;
1039 slide_data->spline = spline;
1040 slide_data->point = point;
1041 slide_data->u = u;
1042
1043 copy_v2_v2(slide_data->prev_mouse_coord, co);
1044 BKE_mask_point_segment_co(spline, point, u, slide_data->prev_spline_coord);
1045
1046 copy_v2_v2(slide_data->P0, point->bezt.vec[1]);
1047 copy_v2_v2(slide_data->P1, point->bezt.vec[2]);
1048 copy_v2_v2(slide_data->P2, next_bezt->vec[0]);
1049 copy_v2_v2(slide_data->P3, next_bezt->vec[1]);
1050
1051 /* Depending to which end we're closer to adjust either left or right side of the spline. */
1052 if (u <= 0.5f) {
1053 slide_data->adjust_bezt = &point->bezt;
1054 slide_data->other_bezt = next_bezt;
1055 }
1056 else {
1057 slide_data->adjust_bezt = next_bezt;
1058 slide_data->other_bezt = &point->bezt;
1059 }
1060
1061 /* Data needed for restoring state. */
1062 slide_data->bezt_backup = *slide_data->adjust_bezt;
1063 slide_data->other_bezt_backup = *slide_data->other_bezt;
1064
1065 /* Let's don't touch other side of the point for now, so set handle to FREE. */
1066 if (u < 0.5f) {
1067 if (slide_data->adjust_bezt->h2 <= HD_VECT) {
1068 slide_data->adjust_bezt->h2 = HD_FREE;
1069 }
1070 }
1071 else {
1072 if (slide_data->adjust_bezt->h1 <= HD_VECT) {
1073 slide_data->adjust_bezt->h1 = HD_FREE;
1074 }
1075 }
1076
1077 /* Change selection */
1079 slide_data->adjust_bezt->f2 |= SELECT;
1080 slide_data->other_bezt->f2 |= SELECT;
1081 if (u < 0.5f) {
1082 slide_data->adjust_bezt->f3 |= SELECT;
1083 slide_data->other_bezt->f1 |= SELECT;
1084 }
1085 else {
1086 slide_data->adjust_bezt->f1 |= SELECT;
1087 slide_data->other_bezt->f3 |= SELECT;
1088 }
1089 mask_layer->act_spline = spline;
1090 mask_layer->act_point = point;
1092
1093 DEG_id_tag_update(&mask->id, 0);
1095
1096 return slide_data;
1097}
1098
1100{
1101 Mask *mask = CTX_data_edit_mask(C);
1102 SlideSplineCurvatureData *slide_data;
1103
1104 if (mask == nullptr) {
1105 return OPERATOR_PASS_THROUGH;
1106 }
1107
1108 /* Be sure we don't conflict with point slide here. */
1109 if (!slide_spline_curvature_check(C, event)) {
1110 return OPERATOR_PASS_THROUGH;
1111 }
1112
1113 slide_data = slide_spline_curvature_customdata(C, event);
1114 if (slide_data != nullptr) {
1115 op->customdata = slide_data;
1119 }
1120
1121 return OPERATOR_PASS_THROUGH;
1122}
1123
1124static void slide_spline_solve_P1(const float u,
1125 const float B[2],
1126 const float P0[2],
1127 const float P2[2],
1128 const float P3[2],
1129 float solution[2])
1130{
1131 const float u2 = u * u, u3 = u * u * u;
1132 const float v = 1.0f - u;
1133 const float v2 = v * v, v3 = v * v * v;
1134 const float inv_divider = 1.0f / (3.0f * v2 * u);
1135 const float t = 3.0f * v * u2;
1136 solution[0] = -(v3 * P0[0] + t * P2[0] + u3 * P3[0] - B[0]) * inv_divider;
1137 solution[1] = -(v3 * P0[1] + t * P2[1] + u3 * P3[1] - B[1]) * inv_divider;
1138}
1139
1140static void slide_spline_solve_P2(const float u,
1141 const float B[2],
1142 const float P0[2],
1143 const float P1[2],
1144 const float P3[2],
1145 float solution[2])
1146{
1147 const float u2 = u * u, u3 = u * u * u;
1148 const float v = 1.0f - u;
1149 const float v2 = v * v, v3 = v * v * v;
1150 const float inv_divider = 1.0f / (3.0f * v * u2);
1151 const float t = 3.0f * v2 * u;
1152 solution[0] = -(v3 * P0[0] + t * P1[0] + u3 * P3[0] - B[0]) * inv_divider;
1153 solution[1] = -(v3 * P0[1] + t * P1[1] + u3 * P3[1] - B[1]) * inv_divider;
1154}
1155
1157{
1158 Scene *scene = CTX_data_scene(C);
1159 const float margin = 0.2f;
1161 float u = slide_data->u;
1162
1163 switch (event->type) {
1164 case EVT_LEFTSHIFTKEY:
1165 case EVT_RIGHTSHIFTKEY:
1166 case EVT_LEFTCTRLKEY:
1167 case EVT_RIGHTCTRLKEY:
1169 slide_data->accurate = (event->val == KM_PRESS);
1170 }
1171
1172 if (ELEM(event->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
1173 if (event->val == KM_PRESS) {
1174 slide_data->adjust_bezt->h1 = slide_data->adjust_bezt->h2 = HD_FREE;
1175 if ((u > margin && u < 0.5f) || (u >= 0.5f && u < 1.0f - margin)) {
1176 slide_data->other_bezt->h1 = slide_data->other_bezt->h2 = HD_FREE;
1177 }
1178 }
1179 else if (event->val == KM_RELEASE) {
1180 slide_data->adjust_bezt->h1 = slide_data->bezt_backup.h1;
1181 slide_data->adjust_bezt->h2 = slide_data->bezt_backup.h2;
1182 slide_data->other_bezt->h1 = slide_data->other_bezt_backup.h1;
1183 slide_data->other_bezt->h2 = slide_data->other_bezt_backup.h2;
1184 }
1185
1186 if (u < 0.5f) {
1187 copy_v2_v2(slide_data->adjust_bezt->vec[0], slide_data->bezt_backup.vec[0]);
1188 copy_v2_v2(slide_data->other_bezt->vec[2], slide_data->other_bezt_backup.vec[2]);
1189 }
1190 else {
1191 copy_v2_v2(slide_data->adjust_bezt->vec[2], slide_data->bezt_backup.vec[2]);
1192 copy_v2_v2(slide_data->other_bezt->vec[0], slide_data->other_bezt_backup.vec[0]);
1193 }
1194 }
1195
1196 ATTR_FALLTHROUGH; /* update CV position */
1197 case MOUSEMOVE: {
1198 float B[2], mouse_coord[2], delta[2];
1199
1200 /* Get coordinate spline is expected to go through. */
1201 ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, mouse_coord);
1202 sub_v2_v2v2(delta, mouse_coord, slide_data->prev_mouse_coord);
1203 if (slide_data->accurate) {
1204 mul_v2_fl(delta, 0.2f);
1205 }
1206 add_v2_v2v2(B, slide_data->prev_spline_coord, delta);
1207 copy_v2_v2(slide_data->prev_spline_coord, B);
1208 copy_v2_v2(slide_data->prev_mouse_coord, mouse_coord);
1209
1210 if (u < 0.5f) {
1211 float oldP2[2];
1212 bool need_restore_P2 = false;
1213
1214 if (u > margin) {
1215 float solution[2];
1216 float x = (u - margin) * 0.5f / (0.5f - margin);
1217 float weight = (3 * x * x - 2 * x * x * x);
1218
1219 slide_spline_solve_P2(u, B, slide_data->P0, slide_data->P1, slide_data->P3, solution);
1220
1221 copy_v2_v2(oldP2, slide_data->P2);
1222 interp_v2_v2v2(slide_data->P2, slide_data->P2, solution, weight);
1223 copy_v2_v2(slide_data->other_bezt->vec[0], slide_data->P2);
1224 need_restore_P2 = true;
1225
1226 /* Tweak handle type in order to be able to apply the delta. */
1227 if (weight > 0.0f) {
1228 if (slide_data->other_bezt->h1 <= HD_VECT) {
1229 slide_data->other_bezt->h1 = HD_FREE;
1230 }
1231 }
1232 }
1233
1235 u, B, slide_data->P0, slide_data->P2, slide_data->P3, slide_data->adjust_bezt->vec[2]);
1236
1237 if (need_restore_P2) {
1238 copy_v2_v2(slide_data->P2, oldP2);
1239 }
1240 }
1241 else {
1242 float oldP1[2];
1243 bool need_restore_P1 = false;
1244
1245 if (u < 1.0f - margin) {
1246 float solution[2];
1247 float x = ((1.0f - u) - margin) * 0.5f / (0.5f - margin);
1248 float weight = 3 * x * x - 2 * x * x * x;
1249
1250 slide_spline_solve_P1(u, B, slide_data->P0, slide_data->P2, slide_data->P3, solution);
1251
1252 copy_v2_v2(oldP1, slide_data->P1);
1253 interp_v2_v2v2(slide_data->P1, slide_data->P1, solution, weight);
1254 copy_v2_v2(slide_data->other_bezt->vec[2], slide_data->P1);
1255 need_restore_P1 = true;
1256
1257 /* Tweak handle type in order to be able to apply the delta. */
1258 if (weight > 0.0f) {
1259 if (slide_data->other_bezt->h2 <= HD_VECT) {
1260 slide_data->other_bezt->h2 = HD_FREE;
1261 }
1262 }
1263 }
1264
1266 u, B, slide_data->P0, slide_data->P1, slide_data->P3, slide_data->adjust_bezt->vec[0]);
1267
1268 if (need_restore_P1) {
1269 copy_v2_v2(slide_data->P1, oldP1);
1270 }
1271 }
1272
1273 WM_event_add_notifier(C, NC_MASK | NA_EDITED, slide_data->mask);
1274 DEG_id_tag_update(&slide_data->mask->id, 0);
1275
1276 break;
1277 }
1278
1279 case LEFTMOUSE:
1280 case RIGHTMOUSE:
1281 if (event->type == slide_data->event_invoke_type && event->val == KM_RELEASE) {
1282 /* Don't key sliding feather UW's. */
1284 ED_mask_layer_shape_auto_key(slide_data->mask_layer, scene->r.cfra);
1285 }
1286
1287 WM_event_add_notifier(C, NC_MASK | NA_EDITED, slide_data->mask);
1288 DEG_id_tag_update(&slide_data->mask->id, 0);
1289
1290 free_slide_spline_curvature_data(slide_data); /* keep this last! */
1291 return OPERATOR_FINISHED;
1292 }
1293
1294 break;
1295
1296 case EVT_ESCKEY:
1298
1299 WM_event_add_notifier(C, NC_MASK | NA_EDITED, slide_data->mask);
1300 DEG_id_tag_update(&slide_data->mask->id, 0);
1301
1302 free_slide_spline_curvature_data(slide_data); /* keep this last! */
1303 return OPERATOR_CANCELLED;
1304 }
1305
1307}
1308
1310{
1311 /* identifiers */
1312 ot->name = "Slide Spline Curvature";
1313 ot->description = "Slide a point on the spline to define its curvature";
1314 ot->idname = "MASK_OT_slide_spline_curvature";
1315
1316 /* api callbacks */
1320
1321 /* flags */
1323}
1324
1325/******************** toggle cyclic *********************/
1326
1328{
1329 Mask *mask = CTX_data_edit_mask(C);
1330
1331 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
1332 if (mask_layer->visibility_flag & (MASK_HIDE_VIEW | MASK_HIDE_SELECT)) {
1333 continue;
1334 }
1335
1336 LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
1337 if (ED_mask_spline_select_check(spline)) {
1338 spline->flag ^= MASK_SPLINE_CYCLIC;
1339 }
1340 }
1341 }
1342
1343 DEG_id_tag_update(&mask->id, 0);
1345
1346 return OPERATOR_FINISHED;
1347}
1348
1350{
1351 /* identifiers */
1352 ot->name = "Toggle Cyclic";
1353 ot->description = "Toggle cyclic for selected splines";
1354 ot->idname = "MASK_OT_cyclic_toggle";
1355
1356 /* api callbacks */
1359
1360 /* flags */
1362}
1363
1364/******************** delete *********************/
1365
1367{
1368 int count = 0;
1369
1370 if (!point->tot_uw) {
1371 return;
1372 }
1373
1374 for (int i = 0; i < point->tot_uw; i++) {
1375 if ((point->uw[i].flag & SELECT) == 0) {
1376 count++;
1377 }
1378 }
1379
1380 if (count == 0) {
1381 MEM_freeN(point->uw);
1382 point->uw = nullptr;
1383 point->tot_uw = 0;
1384 }
1385 else {
1386 MaskSplinePointUW *new_uw;
1387 int j = 0;
1388
1389 new_uw = MEM_cnew_array<MaskSplinePointUW>(count, "new mask uw points");
1390
1391 for (int i = 0; i < point->tot_uw; i++) {
1392 if ((point->uw[i].flag & SELECT) == 0) {
1393 new_uw[j++] = point->uw[i];
1394 }
1395 }
1396
1397 MEM_freeN(point->uw);
1398
1399 point->uw = new_uw;
1400 point->tot_uw = count;
1401 }
1402}
1403
1404static int delete_exec(bContext *C, wmOperator * /*op*/)
1405{
1406 Mask *mask = CTX_data_edit_mask(C);
1407 bool changed = false;
1408
1409 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
1410 MaskSpline *spline;
1411 int mask_layer_shape_ofs = 0;
1412
1413 if (mask_layer->visibility_flag & (MASK_HIDE_VIEW | MASK_HIDE_SELECT)) {
1414 continue;
1415 }
1416
1417 spline = static_cast<MaskSpline *>(mask_layer->splines.first);
1418
1419 while (spline) {
1420 const int tot_point_orig = spline->tot_point;
1421 int count = 0;
1422 MaskSpline *next_spline = spline->next;
1423
1424 /* count unselected points */
1425 for (int i = 0; i < spline->tot_point; i++) {
1426 MaskSplinePoint *point = &spline->points[i];
1427
1428 if (!MASKPOINT_ISSEL_ANY(point)) {
1429 count++;
1430 }
1431 }
1432
1433 if (count == 0) {
1434
1435 /* Update active. */
1436 if (mask_layer->act_point) {
1437 if (ARRAY_HAS_ITEM(mask_layer->act_point, spline->points, spline->tot_point)) {
1438 mask_layer->act_point = nullptr;
1439 }
1440 }
1441 if (spline == mask_layer->act_spline) {
1442 mask_layer->act_spline = nullptr;
1443 }
1444
1445 /* delete the whole spline */
1446 BLI_remlink(&mask_layer->splines, spline);
1447 BKE_mask_spline_free(spline);
1448
1449 BKE_mask_layer_shape_changed_remove(mask_layer, mask_layer_shape_ofs, tot_point_orig);
1450 }
1451 else {
1452 MaskSplinePoint *new_points;
1453
1454 new_points = MEM_cnew_array<MaskSplinePoint>(count, "deleteMaskPoints");
1455
1456 for (int i = 0, j = 0; i < tot_point_orig; i++) {
1457 MaskSplinePoint *point = &spline->points[i];
1458
1459 if (!MASKPOINT_ISSEL_ANY(point)) {
1460 if (point == mask_layer->act_point) {
1461 mask_layer->act_point = &new_points[j];
1462 }
1463
1464 delete_feather_points(point);
1465
1466 new_points[j] = *point;
1467 j++;
1468 }
1469 else {
1470 if (point == mask_layer->act_point) {
1471 mask_layer->act_point = nullptr;
1472 }
1473
1474 BKE_mask_point_free(point);
1475 spline->tot_point--;
1476
1477 BKE_mask_layer_shape_changed_remove(mask_layer, mask_layer_shape_ofs + j, 1);
1478 }
1479 }
1480
1481 mask_layer_shape_ofs += spline->tot_point;
1482
1483 MEM_freeN(spline->points);
1484 spline->points = new_points;
1485
1487 }
1488
1489 changed = true;
1490 spline = next_spline;
1491 }
1492
1493 /* Not essential but confuses users when there are keys with no data!
1494 * Assume if they delete all data from the layer they also don't care about keys. */
1495 if (BLI_listbase_is_empty(&mask_layer->splines)) {
1496 BKE_mask_layer_free_shapes(mask_layer);
1497 }
1498 }
1499
1500 if (!changed) {
1501 return OPERATOR_CANCELLED;
1502 }
1503
1505
1507
1508 return OPERATOR_FINISHED;
1509}
1510
1511static int delete_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
1512{
1513 if (RNA_boolean_get(op->ptr, "confirm")) {
1514 return WM_operator_confirm_ex(C,
1515 op,
1516 IFACE_("Delete selected control points and splines?"),
1517 nullptr,
1518 IFACE_("Delete"),
1520 false);
1521 }
1522 return delete_exec(C, op);
1523}
1524
1526{
1527 /* identifiers */
1528 ot->name = "Delete";
1529 ot->description = "Delete selected control points or splines";
1530 ot->idname = "MASK_OT_delete";
1531
1532 /* api callbacks */
1534 ot->exec = delete_exec;
1536
1537 /* flags */
1540}
1541
1542/* *** switch direction *** */
1544{
1545 Scene *scene = CTX_data_scene(C);
1546 Mask *mask = CTX_data_edit_mask(C);
1547
1548 bool changed = false;
1549
1550 /* do actual selection */
1551 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
1552 bool changed_layer = false;
1553
1554 if (mask_layer->visibility_flag & (MASK_HIDE_VIEW | MASK_HIDE_SELECT)) {
1555 continue;
1556 }
1557
1558 LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
1559 if (ED_mask_spline_select_check(spline)) {
1560 BKE_mask_spline_direction_switch(mask_layer, spline);
1561 changed = true;
1562 changed_layer = true;
1563 }
1564 }
1565
1566 if (changed_layer) {
1568 ED_mask_layer_shape_auto_key(mask_layer, scene->r.cfra);
1569 }
1570 }
1571 }
1572
1573 if (changed) {
1575
1578
1579 return OPERATOR_FINISHED;
1580 }
1581
1582 return OPERATOR_CANCELLED;
1583}
1584
1586{
1587 /* identifiers */
1588 ot->name = "Switch Direction";
1589 ot->description = "Switch direction of selected splines";
1590 ot->idname = "MASK_OT_switch_direction";
1591
1592 /* api callbacks */
1595
1596 /* flags */
1598}
1599
1600/* *** recalc normals *** */
1602{
1603 Scene *scene = CTX_data_scene(C);
1604 Mask *mask = CTX_data_edit_mask(C);
1605
1606 bool changed = false;
1607
1608 /* do actual selection */
1609 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
1610 bool changed_layer = false;
1611
1612 if (mask_layer->visibility_flag & (MASK_HIDE_VIEW | MASK_HIDE_SELECT)) {
1613 continue;
1614 }
1615
1616 LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
1617 for (int i = 0; i < spline->tot_point; i++) {
1618 MaskSplinePoint *point = &spline->points[i];
1619
1620 if (MASKPOINT_ISSEL_ANY(point)) {
1621 BKE_mask_calc_handle_point_auto(spline, point, false);
1622 changed = true;
1623 changed_layer = true;
1624 }
1625 }
1626 }
1627
1628 if (changed_layer) {
1630 ED_mask_layer_shape_auto_key(mask_layer, scene->r.cfra);
1631 }
1632 }
1633 }
1634
1635 if (changed) {
1637
1640
1641 return OPERATOR_FINISHED;
1642 }
1643
1644 return OPERATOR_CANCELLED;
1645}
1646
1648{
1649 /* identifiers */
1650 ot->name = "Recalculate Handles";
1651 ot->description = "Recalculate the direction of selected handles";
1652 ot->idname = "MASK_OT_normals_make_consistent";
1653
1654 /* api callbacks */
1657
1658 /* flags */
1660}
1661
1662/******************** set handle type *********************/
1663
1665{
1666 Mask *mask = CTX_data_edit_mask(C);
1667 int handle_type = RNA_enum_get(op->ptr, "type");
1668
1669 bool changed = false;
1670
1671 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
1672 if (mask_layer->visibility_flag & (MASK_HIDE_VIEW | MASK_HIDE_SELECT)) {
1673 continue;
1674 }
1675
1676 LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
1677 for (int i = 0; i < spline->tot_point; i++) {
1678 MaskSplinePoint *point = &spline->points[i];
1679
1680 if (MASKPOINT_ISSEL_ANY(point)) {
1681 BezTriple *bezt = &point->bezt;
1682
1683 if (bezt->f2 & SELECT) {
1684 bezt->h1 = handle_type;
1685 bezt->h2 = handle_type;
1686 }
1687 else {
1688 if (bezt->f1 & SELECT) {
1689 bezt->h1 = handle_type;
1690 }
1691 if (bezt->f3 & SELECT) {
1692 bezt->h2 = handle_type;
1693 }
1694 }
1695
1696 if (handle_type == HD_ALIGN) {
1697 float vec[3];
1698 sub_v3_v3v3(vec, bezt->vec[0], bezt->vec[1]);
1699 add_v3_v3v3(bezt->vec[2], bezt->vec[1], vec);
1700 }
1701
1702 changed = true;
1703 }
1704 }
1705 }
1706 }
1707
1708 if (changed) {
1710 DEG_id_tag_update(&mask->id, 0);
1711
1712 return OPERATOR_FINISHED;
1713 }
1714 return OPERATOR_CANCELLED;
1715}
1716
1718{
1719 static const EnumPropertyItem editcurve_handle_type_items[] = {
1720 {HD_AUTO, "AUTO", 0, "Auto", ""},
1721 {HD_VECT, "VECTOR", 0, "Vector", ""},
1722 {HD_ALIGN, "ALIGNED", 0, "Aligned Single", ""},
1723 {HD_ALIGN_DOUBLESIDE, "ALIGNED_DOUBLESIDE", 0, "Aligned", ""},
1724 {HD_FREE, "FREE", 0, "Free", ""},
1725 {0, nullptr, 0, nullptr, nullptr},
1726 };
1727
1728 /* identifiers */
1729 ot->name = "Set Handle Type";
1730 ot->description = "Set type of handles for selected control points";
1731 ot->idname = "MASK_OT_handle_type_set";
1732
1733 /* api callbacks */
1737
1738 /* flags */
1740
1741 /* properties */
1742 ot->prop = RNA_def_enum(ot->srna, "type", editcurve_handle_type_items, 1, "Type", "Spline type");
1743}
1744
1745/* ********* clear/set restrict view *********/
1747{
1748 Mask *mask = CTX_data_edit_mask(C);
1749 bool changed = false;
1750 const bool select = RNA_boolean_get(op->ptr, "select");
1751
1752 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
1753
1754 if (mask_layer->visibility_flag & OB_HIDE_VIEWPORT) {
1755 ED_mask_layer_select_set(mask_layer, select);
1756 mask_layer->visibility_flag &= ~OB_HIDE_VIEWPORT;
1757 changed = true;
1758 }
1759 }
1760
1761 if (changed) {
1763 DEG_id_tag_update(&mask->id, 0);
1764
1765 return OPERATOR_FINISHED;
1766 }
1767 return OPERATOR_CANCELLED;
1768}
1769
1771{
1772
1773 /* identifiers */
1774 ot->name = "Clear Restrict View";
1775 ot->description = "Reveal temporarily hidden mask layers";
1776 ot->idname = "MASK_OT_hide_view_clear";
1777
1778 /* api callbacks */
1781
1782 /* flags */
1784
1785 RNA_def_boolean(ot->srna, "select", true, "Select", "");
1786}
1787
1789{
1790 Mask *mask = CTX_data_edit_mask(C);
1791 const bool unselected = RNA_boolean_get(op->ptr, "unselected");
1792 bool changed = false;
1793
1794 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
1795
1796 if (mask_layer->visibility_flag & MASK_HIDE_SELECT) {
1797 continue;
1798 }
1799
1800 if (!unselected) {
1801 if (ED_mask_layer_select_check(mask_layer)) {
1802 ED_mask_layer_select_set(mask_layer, false);
1803
1804 mask_layer->visibility_flag |= OB_HIDE_VIEWPORT;
1805 changed = true;
1806 if (mask_layer == BKE_mask_layer_active(mask)) {
1807 BKE_mask_layer_active_set(mask, nullptr);
1808 }
1809 }
1810 }
1811 else {
1812 if (!ED_mask_layer_select_check(mask_layer)) {
1813 mask_layer->visibility_flag |= OB_HIDE_VIEWPORT;
1814 changed = true;
1815 if (mask_layer == BKE_mask_layer_active(mask)) {
1816 BKE_mask_layer_active_set(mask, nullptr);
1817 }
1818 }
1819 }
1820 }
1821
1822 if (changed) {
1824 DEG_id_tag_update(&mask->id, 0);
1825
1826 return OPERATOR_FINISHED;
1827 }
1828 return OPERATOR_CANCELLED;
1829}
1830
1832{
1833 /* identifiers */
1834 ot->name = "Set Restrict View";
1835 ot->description = "Temporarily hide mask layers";
1836 ot->idname = "MASK_OT_hide_view_set";
1837
1838 /* api callbacks */
1841
1842 /* flags */
1844
1846 ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected layers");
1847}
1848
1850{
1851 Mask *mask = CTX_data_edit_mask(C);
1852 bool changed = false;
1853
1854 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
1855 if (mask_layer->visibility_flag & (MASK_HIDE_SELECT | MASK_HIDE_VIEW)) {
1856 continue;
1857 }
1858
1859 LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
1860 for (int i = 0; i < spline->tot_point; i++) {
1861 MaskSplinePoint *point = &spline->points[i];
1862
1863 if (MASKPOINT_ISSEL_ANY(point)) {
1864 BezTriple *bezt = &point->bezt;
1865 bezt->weight = 0.0f;
1866 changed = true;
1867 }
1868 }
1869 }
1870 }
1871
1872 if (changed) {
1874
1876 DEG_id_tag_update(&mask->id, 0);
1877
1878 return OPERATOR_FINISHED;
1879 }
1880 return OPERATOR_CANCELLED;
1881}
1882
1884{
1885 /* identifiers */
1886 ot->name = "Clear Feather Weight";
1887 ot->description = "Reset the feather weight to zero";
1888 ot->idname = "MASK_OT_feather_weight_clear";
1889
1890 /* api callbacks */
1893
1894 /* flags */
1896}
1897
1898/******************** move mask layer operator *********************/
1899
1901{
1902 if (ED_maskedit_mask_poll(C)) {
1903 Mask *mask = CTX_data_edit_mask(C);
1904
1905 return mask->masklay_tot > 0;
1906 }
1907
1908 return false;
1909}
1910
1912{
1913 Mask *mask = CTX_data_edit_mask(C);
1914 MaskLayer *mask_layer = static_cast<MaskLayer *>(
1915 BLI_findlink(&mask->masklayers, mask->masklay_act));
1916 MaskLayer *mask_layer_other;
1917 int direction = RNA_enum_get(op->ptr, "direction");
1918
1919 if (!mask_layer) {
1920 return OPERATOR_CANCELLED;
1921 }
1922
1923 if (direction == -1) {
1924 mask_layer_other = mask_layer->prev;
1925
1926 if (!mask_layer_other) {
1927 return OPERATOR_CANCELLED;
1928 }
1929
1930 BLI_remlink(&mask->masklayers, mask_layer);
1931 BLI_insertlinkbefore(&mask->masklayers, mask_layer_other, mask_layer);
1932 mask->masklay_act--;
1933 }
1934 else if (direction == 1) {
1935 mask_layer_other = mask_layer->next;
1936
1937 if (!mask_layer_other) {
1938 return OPERATOR_CANCELLED;
1939 }
1940
1941 BLI_remlink(&mask->masklayers, mask_layer);
1942 BLI_insertlinkafter(&mask->masklayers, mask_layer_other, mask_layer);
1943 mask->masklay_act++;
1944 }
1945
1948
1949 return OPERATOR_FINISHED;
1950}
1951
1953{
1954 static const EnumPropertyItem direction_items[] = {
1955 {-1, "UP", 0, "Up", ""},
1956 {1, "DOWN", 0, "Down", ""},
1957 {0, nullptr, 0, nullptr, nullptr},
1958 };
1959
1960 /* identifiers */
1961 ot->name = "Move Layer";
1962 ot->description = "Move the active layer up/down in the list";
1963 ot->idname = "MASK_OT_layer_move";
1964
1965 /* api callbacks */
1968
1969 /* flags */
1971
1972 /* properties */
1974 "direction",
1975 direction_items,
1976 0,
1977 "Direction",
1978 "Direction to move the active layer");
1979}
1980
1981/******************** duplicate *********************/
1982
1984{
1985 Mask *mask = CTX_data_edit_mask(C);
1986
1987 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
1988 LISTBASE_FOREACH_BACKWARD (MaskSpline *, spline, &mask_layer->splines) {
1989 const bool act_point_in_spline = mask_layer->act_point &&
1990 ARRAY_HAS_ITEM(mask_layer->act_point,
1991 spline->points,
1992 spline->tot_point);
1993 const void *act_point_prev = mask_layer->act_point;
1994
1995 MaskSplinePoint *point = spline->points;
1996 int i = 0;
1997 while (i < spline->tot_point) {
1998 int start = i, end = -1;
1999 /* Find next selected segment. */
2000 while (MASKPOINT_ISSEL_ANY(point)) {
2001 BKE_mask_point_select_set(point, false);
2002 end = i;
2003 if (i >= spline->tot_point - 1) {
2004 break;
2005 }
2006 i++;
2007 point++;
2008 }
2009 if (end >= start) {
2010 int tot_point;
2011 int tot_point_shape_start = 0;
2012 MaskSpline *new_spline = BKE_mask_spline_add(mask_layer);
2013 MaskSplinePoint *new_point;
2014 int b;
2015
2016 /* BKE_mask_spline_add might allocate the points,
2017 * need to free them in this case. */
2018 if (new_spline->points) {
2019 MEM_freeN(new_spline->points);
2020 }
2021
2022 /* Copy options from old spline. */
2023 new_spline->flag = spline->flag;
2024 new_spline->offset_mode = spline->offset_mode;
2025 new_spline->weight_interp = spline->weight_interp;
2026 new_spline->parent = spline->parent;
2027
2028 /* Allocate new points and copy them from old spline. */
2029 new_spline->tot_point = end - start + 1;
2030 new_spline->points = MEM_cnew_array<MaskSplinePoint>(new_spline->tot_point,
2031 "duplicated mask points");
2032
2033 memcpy(new_spline->points,
2034 spline->points + start,
2035 new_spline->tot_point * sizeof(MaskSplinePoint));
2036
2037 tot_point = new_spline->tot_point;
2038
2039 /* Update the active. */
2040 if (mask_layer->act_point) {
2041 ptrdiff_t act_index = mask_layer->act_point - &spline->points[start];
2042 if (size_t(act_index) < new_spline->tot_point) {
2043 mask_layer->act_point = &new_spline->points[act_index];
2044 }
2045 }
2046 if (mask_layer->act_spline) {
2047 if (mask_layer->act_spline == spline) {
2048 mask_layer->act_spline = new_spline;
2049 }
2050 }
2051
2052 /* animation requires points added one by one */
2053 if (mask_layer->splines_shapes.first) {
2054 new_spline->tot_point = 0;
2055 tot_point_shape_start = BKE_mask_layer_shape_spline_to_index(mask_layer, new_spline);
2056 }
2057
2058 /* Select points and duplicate their UWs (if needed). */
2059 for (b = 0, new_point = new_spline->points; b < tot_point; b++, new_point++) {
2060 if (new_point->uw) {
2061 new_point->uw = static_cast<MaskSplinePointUW *>(MEM_dupallocN(new_point->uw));
2062 }
2063 BKE_mask_point_select_set(new_point, true);
2064
2065 if (mask_layer->splines_shapes.first) {
2066 new_spline->tot_point++;
2067 BKE_mask_layer_shape_changed_add(mask_layer, tot_point_shape_start + b, true, false);
2068 }
2069 }
2070
2071 /* Clear cyclic flag if we didn't copy the whole spline. */
2072 if (new_spline->flag & MASK_SPLINE_CYCLIC) {
2073 if (start != 0 || end != spline->tot_point - 1) {
2074 new_spline->flag &= ~MASK_SPLINE_CYCLIC;
2075 }
2076 }
2077
2078 /* Flush selection to splines. */
2079 new_spline->flag |= SELECT;
2080 spline->flag &= ~SELECT;
2081 }
2082 i++;
2083 point++;
2084 }
2085
2086 if (act_point_in_spline && (mask_layer->act_point == act_point_prev)) {
2087 /* The active point was part of this spline but not copied,
2088 * clear it to avoid confusion with the active spline & point getting out of sync. */
2089 mask_layer->act_point = nullptr;
2090 }
2091 }
2092 }
2093
2095
2097
2098 return OPERATOR_FINISHED;
2099}
2100
2102{
2103 /* identifiers */
2104 ot->name = "Duplicate Mask";
2105 ot->description = "Duplicate selected control points and segments between them";
2106 ot->idname = "MASK_OT_duplicate";
2107
2108 /* api callbacks */
2111
2112 /* flags */
2114}
2115
2116/********************** copy splines to clipboard operator *********************/
2117
2118static int copy_splines_exec(bContext *C, wmOperator * /*op*/)
2119{
2120 Mask *mask = CTX_data_edit_mask(C);
2121 MaskLayer *mask_layer = BKE_mask_layer_active(mask);
2122
2123 if (mask_layer == nullptr) {
2124 return OPERATOR_CANCELLED;
2125 }
2126
2128
2129 return OPERATOR_FINISHED;
2130}
2131
2133{
2134 /* identifiers */
2135 ot->name = "Copy Splines";
2136 ot->description = "Copy the selected splines to the internal clipboard";
2137 ot->idname = "MASK_OT_copy_splines";
2138
2139 /* api callbacks */
2142
2143 /* flags */
2145}
2146
2147/********************** paste tracks from clipboard operator *********************/
2148
2150{
2152 return BKE_mask_clipboard_is_empty() == false;
2153 }
2154
2155 return false;
2156}
2157
2159{
2160 Mask *mask = CTX_data_edit_mask(C);
2161 MaskLayer *mask_layer = BKE_mask_layer_active(mask);
2162
2163 if (mask_layer == nullptr) {
2164 mask_layer = BKE_mask_layer_new(mask, "");
2165 }
2166
2168
2170
2172
2173 return OPERATOR_FINISHED;
2174}
2175
2177{
2178 /* identifiers */
2179 ot->name = "Paste Splines";
2180 ot->description = "Paste splines from the internal clipboard";
2181 ot->idname = "MASK_OT_paste_splines";
2182
2183 /* api callbacks */
2186
2187 /* flags */
2189}
Functions to insert, delete or modify keyframes.
Mask * CTX_data_edit_mask(const bContext *C)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
SpaceClip * CTX_wm_space_clip(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
struct Mask * BKE_mask_new(struct Main *bmain, const char *name)
#define MASKPOINT_ISSEL_ANY(p)
Definition BKE_mask.h:297
void BKE_mask_layer_shape_changed_add(struct MaskLayer *masklay, int index, bool do_init, bool do_init_interpolate)
struct MaskSplinePointUW * BKE_mask_point_sort_uw(struct MaskSplinePoint *point, struct MaskSplinePointUW *uw)
void BKE_mask_layer_remove(struct Mask *mask, struct MaskLayer *masklay)
void BKE_mask_point_select_set(struct MaskSplinePoint *point, bool do_select)
void BKE_mask_calc_handle_point_auto(struct MaskSpline *spline, struct MaskSplinePoint *point, bool do_recalc_length)
Resets auto handles even for non-auto bezier points.
eMaskWhichHandle
Definition BKE_mask.h:32
@ MASK_WHICH_HANDLE_NONE
Definition BKE_mask.h:33
@ MASK_WHICH_HANDLE_RIGHT
Definition BKE_mask.h:36
@ MASK_WHICH_HANDLE_LEFT
Definition BKE_mask.h:35
@ MASK_WHICH_HANDLE_STICK
Definition BKE_mask.h:34
struct MaskSpline * BKE_mask_spline_add(struct MaskLayer *masklay)
struct MaskSpline * BKE_mask_spline_copy(const struct MaskSpline *spline)
void BKE_mask_spline_free(struct MaskSpline *spline)
void BKE_mask_point_free(struct MaskSplinePoint *point)
void BKE_mask_layer_active_set(struct Mask *mask, struct MaskLayer *masklay)
struct BezTriple * BKE_mask_spline_point_next_bezt(struct MaskSpline *spline, struct MaskSplinePoint *points_array, struct MaskSplinePoint *point)
struct MaskLayer * BKE_mask_layer_new(struct Mask *mask, const char *name)
float BKE_mask_point_weight_scalar(struct MaskSpline *spline, struct MaskSplinePoint *point, float u)
void BKE_mask_point_set_handle(struct MaskSplinePoint *point, eMaskWhichHandle which_handle, float loc[2], bool keep_direction, float orig_handle[2], float orig_vec[3][3])
@ MASK_PROJ_NEG
Definition BKE_mask.h:96
@ MASK_PROJ_POS
Definition BKE_mask.h:98
void BKE_mask_clipboard_paste_to_layer(struct Main *bmain, struct MaskLayer *mask_layer)
void BKE_mask_coord_to_movieclip(struct MovieClip *clip, struct MovieClipUser *user, float r_co[2], const float co[2])
void BKE_mask_layer_free_shapes(struct MaskLayer *masklay)
Free all animation keys for a mask layer.
void BKE_mask_point_handle(const struct MaskSplinePoint *point, eMaskWhichHandle which_handle, float r_handle[2])
void BKE_mask_point_normal(struct MaskSpline *spline, struct MaskSplinePoint *point, float u, float n[2])
void BKE_mask_point_segment_co(struct MaskSpline *spline, struct MaskSplinePoint *point, float u, float co[2])
int BKE_mask_layer_shape_spline_to_index(struct MaskLayer *masklay, struct MaskSpline *spline)
void BKE_mask_coord_from_movieclip(struct MovieClip *clip, struct MovieClipUser *user, float r_co[2], const float co[2])
void BKE_mask_layer_shape_changed_remove(struct MaskLayer *masklay, int index, int count)
bool BKE_mask_clipboard_is_empty(void)
float BKE_mask_spline_project_co(struct MaskSpline *spline, struct MaskSplinePoint *point, float start_u, const float co[2], eMaskSign sign)
struct MaskLayer * BKE_mask_layer_active(struct Mask *mask)
void BKE_mask_clipboard_copy_from_layer(struct MaskLayer *mask_layer)
void BKE_mask_spline_direction_switch(struct MaskLayer *masklay, struct MaskSpline *spline)
struct MaskSplinePoint * BKE_mask_spline_point_array(struct MaskSpline *spline)
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define ATTR_FALLTHROUGH
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:331
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:370
MINLINE float min_ff(float a, float b)
MINLINE float square_f(float a)
void copy_m3_m3(float m1[3][3], const float m2[3][3])
void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2])
MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v2_v2v2fl(float r[2], const float a[2], const float b[2], float f)
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v2_fl(float r[2], float f)
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], float t)
Definition math_vector.c:21
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void negate_v2(float r[2])
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
#define INIT_MINMAX2(min, max)
#define ARRAY_HAS_ITEM(arr_item, arr_start, arr_len)
#define ELEM(...)
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
ID * DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
#define MAX_ID_NAME
Definition DNA_ID.h:377
@ HD_VECT
@ HD_FREE
@ HD_AUTO
@ HD_ALIGN_DOUBLESIDE
@ HD_ALIGN
@ MASK_SPLINE_CYCLIC
@ MASK_HIDE_SELECT
@ MASK_HIDE_VIEW
@ MCLIP_PROXY_RENDER_UNDISTORT
Object is a sort of wrapper for general info.
@ OB_HIDE_VIEWPORT
@ SPACE_CLIP
@ SPACE_SEQ
@ SPACE_IMAGE
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_space_clip_set_mask(bContext *C, SpaceClip *sc, Mask *mask)
void ED_clip_point_undistorted_pos(const SpaceClip *sc, const float co[2], float r_co[2])
void ED_space_image_set_mask(bContext *C, SpaceImage *sima, Mask *mask)
void ED_mask_mouse_pos(ScrArea *area, ARegion *region, const int mval[2], float r_co[2])
void ED_mask_layer_shape_auto_key(MaskLayer *mask_layer, int frame)
void ED_mask_get_size(ScrArea *area, int *r_width, int *r_height)
bool ED_maskedit_mask_poll(bContext *C)
Definition mask_edit.cc:62
bool ED_maskedit_poll(bContext *C)
Definition mask_edit.cc:30
bool ED_maskedit_mask_visible_splines_poll(bContext *C)
Definition mask_edit.cc:78
@ SEL_DESELECT
Read Guarded memory(de)allocation.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ ALERT_ICON_NONE
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_DRAW
Definition WM_types.hh:428
#define ND_DATA
Definition WM_types.hh:475
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
#define NA_ADDED
Definition WM_types.hh:552
#define NA_EDITED
Definition WM_types.hh:550
#define ND_SELECT
Definition WM_types.hh:474
#define NC_MASK
Definition WM_types.hh:365
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
local_group_size(16, 16) .push_constant(Type b
#define SELECT
const Depsgraph * depsgraph
int count
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
void ED_mask_view_lock_state_restore_no_jump(const bContext *C, const MaskViewLockState *state)
Definition mask_edit.cc:217
void ED_mask_view_lock_state_store(const bContext *C, MaskViewLockState *state)
Definition mask_edit.cc:209
bool ED_mask_spline_select_check(const MaskSpline *spline)
MaskSplinePoint * ED_mask_point_find_nearest(const bContext *C, Mask *mask_orig, const float normal_co[2], float threshold, MaskLayer **r_mask_layer, MaskSpline **r_spline, eMaskWhichHandle *r_which_handle, float *r_score)
bool ED_mask_layer_select_check(const MaskLayer *mask_layer)
bool ED_mask_feather_find_nearest(const bContext *C, Mask *mask_orig, const float normal_co[2], float threshold, MaskLayer **r_mask_layer, MaskSpline **r_spline, MaskSplinePoint **r_point, MaskSplinePointUW **r_uw, float *r_score)
void ED_mask_select_flush_all(Mask *mask)
void ED_mask_select_toggle_all(Mask *mask, int action)
void ED_mask_layer_select_set(MaskLayer *mask_layer, bool do_select)
bool ED_mask_find_nearest_diff_point(const bContext *C, Mask *mask_orig, const float normal_co[2], int threshold, bool feather, float tangent[2], bool use_deform, bool use_project, MaskLayer **r_mask_layer, MaskSpline **r_spline, MaskSplinePoint **r_point, float *r_u, float *r_score)
Definition mask_query.cc:36
static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition mask_ops.cc:646
static void cancel_slide_point(SlidePointData *data)
Definition mask_ops.cc:613
static bool paste_splines_poll(bContext *C)
Definition mask_ops.cc:2149
static SlideSplineCurvatureData * slide_spline_curvature_customdata(bContext *C, const wmEvent *event)
Definition mask_ops.cc:995
static void cancel_slide_spline_curvature(SlideSplineCurvatureData *slide_data)
Definition mask_ops.cc:963
static int delete_exec(bContext *C, wmOperator *)
Definition mask_ops.cc:1404
static SlidePointData * slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *event)
Definition mask_ops.cc:423
static int mask_hide_view_set_exec(bContext *C, wmOperator *op)
Definition mask_ops.cc:1788
void MASK_OT_slide_spline_curvature(wmOperatorType *ot)
Definition mask_ops.cc:1309
void MASK_OT_copy_splines(wmOperatorType *ot)
Definition mask_ops.cc:2132
static int mask_new_exec(bContext *C, wmOperator *op)
Definition mask_ops.cc:96
static void check_sliding_handle_type(MaskSplinePoint *point, eMaskWhichHandle which_handle)
Definition mask_ops.cc:399
void MASK_OT_layer_move(wmOperatorType *ot)
Definition mask_ops.cc:1952
static int slide_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition mask_ops.cc:559
void MASK_OT_feather_weight_clear(wmOperatorType *ot)
Definition mask_ops.cc:1883
void MASK_OT_layer_remove(wmOperatorType *ot)
Definition mask_ops.cc:180
static bool slide_point_check_initial_feather(MaskSpline *spline)
Definition mask_ops.cc:355
void MASK_OT_paste_splines(wmOperatorType *ot)
Definition mask_ops.cc:2176
static int mask_hide_view_clear_exec(bContext *C, wmOperator *op)
Definition mask_ops.cc:1746
void MASK_OT_layer_new(wmOperatorType *ot)
Definition mask_ops.cc:145
static int copy_splines_exec(bContext *C, wmOperator *)
Definition mask_ops.cc:2118
static bool slide_spline_curvature_check(bContext *C, const wmEvent *event)
Definition mask_ops.cc:974
static int delete_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition mask_ops.cc:1511
static int mask_feather_weight_clear_exec(bContext *C, wmOperator *)
Definition mask_ops.cc:1849
static int slide_spline_curvature_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition mask_ops.cc:1099
static void select_sliding_point(Mask *mask, MaskLayer *mask_layer, MaskSpline *spline, MaskSplinePoint *point, eMaskWhichHandle which_handle)
Definition mask_ops.cc:368
static int set_handle_type_exec(bContext *C, wmOperator *op)
Definition mask_ops.cc:1664
static int cyclic_toggle_exec(bContext *C, wmOperator *)
Definition mask_ops.cc:1327
@ SLIDE_ACTION_NONE
Definition mask_ops.cc:198
@ SLIDE_ACTION_POINT
Definition mask_ops.cc:199
@ SLIDE_ACTION_SPLINE
Definition mask_ops.cc:202
@ SLIDE_ACTION_HANDLE
Definition mask_ops.cc:200
@ SLIDE_ACTION_FEATHER
Definition mask_ops.cc:201
static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float co[2])
Definition mask_ops.cc:244
static void free_slide_spline_curvature_data(SlideSplineCurvatureData *slide_data)
Definition mask_ops.cc:969
MaskLayer * ED_mask_layer_ensure(bContext *C, bool *r_added_mask)
Definition mask_ops.cc:76
static int mask_normals_make_consistent_exec(bContext *C, wmOperator *)
Definition mask_ops.cc:1601
Mask * ED_mask_new(bContext *C, const char *name)
Definition mask_ops.cc:46
static void slide_spline_solve_P1(const float u, const float B[2], const float P0[2], const float P2[2], const float P3[2], float solution[2])
Definition mask_ops.cc:1124
void MASK_OT_hide_view_clear(wmOperatorType *ot)
Definition mask_ops.cc:1770
static bool mask_layer_move_poll(bContext *C)
Definition mask_ops.cc:1900
static int mask_layer_new_exec(bContext *C, wmOperator *op)
Definition mask_ops.cc:129
void MASK_OT_new(wmOperatorType *ot)
Definition mask_ops.cc:109
static int mask_duplicate_exec(bContext *C, wmOperator *)
Definition mask_ops.cc:1983
static void slide_point_delta_all_feather(SlidePointData *data, float delta)
Definition mask_ops.cc:586
void MASK_OT_handle_type_set(wmOperatorType *ot)
Definition mask_ops.cc:1717
void MASK_OT_duplicate(wmOperatorType *ot)
Definition mask_ops.cc:2101
void MASK_OT_cyclic_toggle(wmOperatorType *ot)
Definition mask_ops.cc:1349
static void slide_spline_solve_P2(const float u, const float B[2], const float P0[2], const float P1[2], const float P3[2], float solution[2])
Definition mask_ops.cc:1140
static void free_slide_point_data(SlidePointData *data)
Definition mask_ops.cc:637
void MASK_OT_delete(wmOperatorType *ot)
Definition mask_ops.cc:1525
static void delete_feather_points(MaskSplinePoint *point)
Definition mask_ops.cc:1366
static bool spline_under_mouse_get(const bContext *C, Mask *mask_orig, const float co[2], MaskLayer **r_mask_layer, MaskSpline **r_mask_spline)
Definition mask_ops.cc:251
void MASK_OT_hide_view_set(wmOperatorType *ot)
Definition mask_ops.cc:1831
static int mask_switch_direction_exec(bContext *C, wmOperator *)
Definition mask_ops.cc:1543
static int slide_spline_curvature_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition mask_ops.cc:1156
void MASK_OT_slide_point(wmOperatorType *ot)
Definition mask_ops.cc:914
void MASK_OT_switch_direction(wmOperatorType *ot)
Definition mask_ops.cc:1585
static int mask_layer_remove_exec(bContext *C, wmOperator *)
Definition mask_ops.cc:165
void MASK_OT_normals_make_consistent(wmOperatorType *ot)
Definition mask_ops.cc:1647
static int mask_layer_move_exec(bContext *C, wmOperator *op)
Definition mask_ops.cc:1911
static void slide_point_restore_spline(SlidePointData *data)
Definition mask_ops.cc:599
static int paste_splines_exec(bContext *C, wmOperator *)
Definition mask_ops.cc:2158
ccl_device_inline float4 mask(const int4 mask, const float4 a)
ccl_device_inline float4 select(const int4 mask, const float4 a, const float4 b)
#define B
bool is_autokey_on(const Scene *scene)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
float vec[3][3]
void * first
struct MaskLayer * next
struct MaskLayer * prev
struct MaskSplinePoint * act_point
struct MaskSpline * act_spline
char parent[64]
MaskSplinePointUW * uw
MaskParent parent
struct MaskSpline * next
MaskSplinePoint * points
ListBase masklayers
float vec[3][3]
Definition mask_ops.cc:231
short event_invoke_type
Definition mask_ops.cc:207
float orig_handle_coord[2]
Definition mask_ops.cc:237
float prev_zero_coord[2]
Definition mask_ops.cc:222
float prev_handle_coord[2]
Definition mask_ops.cc:237
float prev_feather_coord[2]
Definition mask_ops.cc:240
eMaskWhichHandle which_handle
Definition mask_ops.cc:214
MaskSpline * spline
Definition mask_ops.cc:211
float weight_scalar
Definition mask_ops.cc:241
bool is_sliding_new_point
Definition mask_ops.cc:228
MaskLayer * mask_layer
Definition mask_ops.cc:210
bool is_curvature_only
Definition mask_ops.cc:226
MaskSplinePoint * point
Definition mask_ops.cc:212
MaskSpline * orig_spline
Definition mask_ops.cc:211
bool is_overall_feather
Definition mask_ops.cc:226
float no[2]
Definition mask_ops.cc:224
MaskSplinePointUW * uw
Definition mask_ops.cc:213
float prev_mouse_coord[2]
Definition mask_ops.cc:217
bool is_initial_feather
Definition mask_ops.cc:226
MaskSplinePoint * point
Definition mask_ops.cc:950
struct MovieClipUser user
struct MovieClip * clip
short val
Definition WM_types.hh:724
int mval[2]
Definition WM_types.hh:728
short type
Definition WM_types.hh:722
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
struct PointerRNA * ptr
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ RIGHTMOUSE
@ EVT_RIGHTCTRLKEY
@ EVT_LEFTCTRLKEY
@ MOUSEMOVE
@ EVT_RIGHTALTKEY
@ LEFTMOUSE
@ EVT_LEFTALTKEY
@ EVT_ESCKEY
@ EVT_RIGHTSHIFTKEY
@ EVT_LEFTSHIFTKEY
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_operator_properties_confirm_or_exec(wmOperatorType *ot)
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)
int WM_operator_confirm_ex(bContext *C, wmOperator *op, const char *title, const char *message, const char *confirm_text, int icon, bool cancel_default)