Blender V5.0
blenkernel/intern/mask.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
8
9#include <cstddef>
10#include <cstring>
11#include <optional>
12
13#include "CLG_log.h"
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_ghash.h"
18#include "BLI_listbase.h"
19#include "BLI_math_geom.h"
20#include "BLI_math_matrix.h"
21#include "BLI_math_vector.h"
22#include "BLI_string_utf8.h"
23#include "BLI_string_utils.hh"
24#include "BLI_utildefines.h"
25
26#include "BLT_translation.hh"
27
28#include "DNA_defaults.h"
29#include "DNA_mask_types.h"
30#include "DNA_movieclip_types.h"
31#include "DNA_object_types.h"
32
33#include "BKE_animsys.h"
34#include "BKE_curve.hh"
35#include "BKE_idtype.hh"
36
37#include "BKE_anim_data.hh"
38#include "BKE_image.hh"
39#include "BKE_lib_id.hh"
40#include "BKE_lib_query.hh"
41#include "BKE_main.hh"
42#include "BKE_mask.h"
43#include "BKE_movieclip.h"
44#include "BKE_tracking.h"
45
47
48#include "DRW_engine.hh"
49
50#include "BLO_read_write.hh"
51
52static CLG_LogRef LOG = {"mask"};
53
56{
57 mask->runtime.last_update = 0;
58}
59
60static void mask_copy_data(Main * /*bmain*/,
61 std::optional<Library *> /*owner_library*/,
62 ID *id_dst,
63 const ID *id_src,
64 const int /*flag*/)
65{
66 Mask *mask_dst = (Mask *)id_dst;
67 const Mask *mask_src = (const Mask *)id_src;
68
70
71 /* TODO: add unused flag to those as well. */
72 BKE_mask_layer_copy_list(&mask_dst->masklayers, &mask_src->masklayers);
73
74 /* enable fake user by default */
75 id_fake_user_set(&mask_dst->id);
76}
77
78static void mask_free_data(ID *id)
79{
80 Mask *mask = (Mask *)id;
81
82 /* free mask data */
83 BKE_mask_layer_free_list(&mask->masklayers);
84}
85
87{
88 Mask *mask = (Mask *)id;
89
90 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
91 LISTBASE_FOREACH (MaskSpline *, mask_spline, &mask_layer->splines) {
92 BKE_LIB_FOREACHID_PROCESS_ID(data, mask_spline->parent.id, IDWALK_CB_USER);
93 for (int i = 0; i < mask_spline->tot_point; i++) {
94 MaskSplinePoint *point = &mask_spline->points[i];
96 }
97 }
98 }
99}
100
101static void mask_blend_write(BlendWriter *writer, ID *id, const void *id_address)
102{
103 Mask *mask = (Mask *)id;
104
105 BLO_write_id_struct(writer, Mask, id_address, &mask->id);
106 BKE_id_blend_write(writer, &mask->id);
107
108 LISTBASE_FOREACH (MaskLayer *, masklay, &mask->masklayers) {
109 BLO_write_struct(writer, MaskLayer, masklay);
110
111 LISTBASE_FOREACH (MaskSpline *, spline, &masklay->splines) {
112 int i;
113
114 MaskSplinePoint *points_deform = spline->points_deform;
115 spline->points_deform = nullptr;
116
117 BLO_write_struct(writer, MaskSpline, spline);
118 BLO_write_struct_array(writer, MaskSplinePoint, spline->tot_point, spline->points);
119
120 spline->points_deform = points_deform;
121
122 for (i = 0; i < spline->tot_point; i++) {
123 MaskSplinePoint *point = &spline->points[i];
124
125 if (point->tot_uw) {
126 BLO_write_struct_array(writer, MaskSplinePointUW, point->tot_uw, point->uw);
127 }
128 }
129 }
130
131 LISTBASE_FOREACH (MaskLayerShape *, masklay_shape, &masklay->splines_shapes) {
132 BLO_write_struct(writer, MaskLayerShape, masklay_shape);
134 writer, masklay_shape->tot_vert * MASK_OBJECT_SHAPE_ELEM_SIZE, masklay_shape->data);
135 }
136 }
137}
138
139static void mask_blend_read_data(BlendDataReader *reader, ID *id)
140{
141 Mask *mask = (Mask *)id;
142
143 BLO_read_struct_list(reader, MaskLayer, &mask->masklayers);
144
145 LISTBASE_FOREACH (MaskLayer *, masklay, &mask->masklayers) {
146 /* Can't use #newdataadr since it's a pointer within an array. */
147 MaskSplinePoint *act_point_search = nullptr;
148
149 BLO_read_struct_list(reader, MaskSpline, &masklay->splines);
150
151 LISTBASE_FOREACH (MaskSpline *, spline, &masklay->splines) {
152 MaskSplinePoint *points_old = spline->points;
153
154 BLO_read_struct_array(reader, MaskSplinePoint, spline->tot_point, &spline->points);
155
156 for (int i = 0; i < spline->tot_point; i++) {
157 MaskSplinePoint *point = &spline->points[i];
158
159 if (point->tot_uw) {
160 BLO_read_struct_array(reader, MaskSplinePointUW, point->tot_uw, &point->uw);
161 }
162 }
163
164 /* detect active point */
165 if ((act_point_search == nullptr) && (masklay->act_point >= points_old) &&
166 (masklay->act_point < points_old + spline->tot_point))
167 {
168 act_point_search = &spline->points[masklay->act_point - points_old];
169 }
170 }
171
172 BLO_read_struct_list(reader, MaskLayerShape, &masklay->splines_shapes);
173
174 LISTBASE_FOREACH (MaskLayerShape *, masklay_shape, &masklay->splines_shapes) {
176 reader, masklay_shape->tot_vert * MASK_OBJECT_SHAPE_ELEM_SIZE, &masklay_shape->data);
177 }
178
179 BLO_read_struct(reader, MaskSpline, &masklay->act_spline);
180 masklay->act_point = act_point_search;
181 }
182
184}
185
187 /*id_code*/ Mask::id_type,
188 /*id_filter*/ FILTER_ID_MSK,
189 /*dependencies_id_types*/ FILTER_ID_MC, /* WARNING! mask->parent.id, not typed. */
190 /*main_listbase_index*/ INDEX_ID_MSK,
191 /*struct_size*/ sizeof(Mask),
192 /*name*/ "Mask",
193 /*name_plural*/ N_("masks"),
194 /*translation_context*/ BLT_I18NCONTEXT_ID_MASK,
196 /*asset_type_info*/ nullptr,
197
198 /*init_data*/ nullptr,
199 /*copy_data*/ mask_copy_data,
200 /*free_data*/ mask_free_data,
201 /*make_local*/ nullptr,
202 /*foreach_id*/ mask_foreach_id,
203 /*foreach_cache*/ nullptr,
204 /*foreach_path*/ nullptr,
205 /*foreach_working_space_color*/ nullptr,
206 /*owner_pointer_get*/ nullptr,
207
208 /*blend_write*/ mask_blend_write,
209 /*blend_read_data*/ mask_blend_read_data,
210 /*blend_read_after_liblink*/ nullptr,
211
212 /*blend_read_undo_preserve*/ nullptr,
213
214 /*lib_override_apply_post*/ nullptr,
215};
216
217static struct {
220} mask_clipboard = {{nullptr}};
221
223 MaskSplinePoint *points_array,
224 MaskSplinePoint *point)
225{
226 if (point == &points_array[spline->tot_point - 1]) {
227 if (spline->flag & MASK_SPLINE_CYCLIC) {
228 return &points_array[0];
229 }
230
231 return nullptr;
232 }
233
234 return point + 1;
235}
236
238 MaskSplinePoint *points_array,
239 MaskSplinePoint *point)
240{
241 if (point == points_array) {
242 if (spline->flag & MASK_SPLINE_CYCLIC) {
243 return &points_array[spline->tot_point - 1];
244 }
245
246 return nullptr;
247 }
248
249 return point - 1;
250}
251
253 MaskSplinePoint *points_array,
254 MaskSplinePoint *point)
255{
256 if (point == &points_array[spline->tot_point - 1]) {
257 if (spline->flag & MASK_SPLINE_CYCLIC) {
258 return &(points_array[0].bezt);
259 }
260
261 return nullptr;
262 }
263
264 return &(point + 1)->bezt;
265}
266
268{
269 return spline->points_deform ? spline->points_deform : spline->points;
270}
271
273 const MaskSplinePoint *point_ref)
274{
275 if ((point_ref >= spline->points) && (point_ref < &spline->points[spline->tot_point])) {
276 return spline->points;
277 }
278
279 if ((point_ref >= spline->points_deform) &&
280 (point_ref < &spline->points_deform[spline->tot_point]))
281 {
282 return spline->points_deform;
283 }
284
285 BLI_assert_msg(0, "wrong array");
286 return nullptr;
287}
288
289/* mask layers */
290
292{
293 MaskLayer *masklay = MEM_callocN<MaskLayer>(__func__);
294
295 STRNCPY_UTF8(masklay->name, name && name[0] ? name : DATA_("MaskLayer"));
296
297 BLI_addtail(&mask->masklayers, masklay);
298
300
301 mask->masklay_tot++;
302
303 masklay->blend = MASK_BLEND_MERGE_ADD;
304 masklay->alpha = 1.0f;
306
307 return masklay;
308}
309
311{
312 return static_cast<MaskLayer *>(BLI_findlink(&mask->masklayers, mask->masklay_act));
313}
314
316{
317 mask->masklay_act = BLI_findindex(&mask->masklayers, masklay);
318}
319
321{
322 BLI_remlink(&mask->masklayers, masklay);
323 BKE_mask_layer_free(masklay);
324
325 mask->masklay_tot--;
326
327 if (mask->masklay_act >= mask->masklay_tot) {
328 mask->masklay_act = mask->masklay_tot - 1;
329 }
330}
331
333{
334 BLI_uniquename(&mask->masklayers,
335 masklay,
336 DATA_("MaskLayer"),
337 '.',
339 sizeof(masklay->name));
340}
341
343 MaskLayer *masklay,
344 const char *oldname,
345 const char *newname)
346{
347 STRNCPY_UTF8(masklay->name, newname);
348
350
351 /* now fix animation paths */
352 BKE_animdata_fix_paths_rename_all(&mask->id, "layers", oldname, masklay->name);
353}
354
356{
357 MaskLayer *masklay_new = MEM_callocN<MaskLayer>("new mask layer");
358
359 STRNCPY_UTF8(masklay_new->name, masklay->name);
360
361 masklay_new->alpha = masklay->alpha;
362 masklay_new->blend = masklay->blend;
363 masklay_new->blend_flag = masklay->blend_flag;
364 masklay_new->flag = masklay->flag;
365 masklay_new->falloff = masklay->falloff;
366 masklay_new->visibility_flag = masklay->visibility_flag;
367
368 LISTBASE_FOREACH (MaskSpline *, spline, &masklay->splines) {
369 MaskSpline *spline_new = BKE_mask_spline_copy(spline);
370
371 BLI_addtail(&masklay_new->splines, spline_new);
372
373 if (spline == masklay->act_spline) {
374 masklay_new->act_spline = spline_new;
375 }
376
377 if (masklay->act_point >= spline->points &&
378 masklay->act_point < spline->points + spline->tot_point)
379 {
380 const size_t point_index = masklay->act_point - spline->points;
381 masklay_new->act_point = spline_new->points + point_index;
382 }
383 }
384
385 /* correct animation */
386 if (masklay->splines_shapes.first) {
387 LISTBASE_FOREACH (MaskLayerShape *, masklay_shape, &masklay->splines_shapes) {
388 MaskLayerShape *masklay_shape_new = MEM_callocN<MaskLayerShape>("new mask layer shape");
389
390 masklay_shape_new->data = static_cast<float *>(MEM_dupallocN(masklay_shape->data));
391 masklay_shape_new->tot_vert = masklay_shape->tot_vert;
392 masklay_shape_new->flag = masklay_shape->flag;
393 masklay_shape_new->frame = masklay_shape->frame;
394
395 BLI_addtail(&masklay_new->splines_shapes, masklay_shape_new);
396 }
397 }
398
399 return masklay_new;
400}
401
402void BKE_mask_layer_copy_list(ListBase *masklayers_new, const ListBase *masklayers)
403{
404 LISTBASE_FOREACH (MaskLayer *, layer, masklayers) {
405 MaskLayer *layer_new = BKE_mask_layer_copy(layer);
406
407 BLI_addtail(masklayers_new, layer_new);
408 }
409}
410
411/* splines */
412
414{
415 MaskSpline *spline = MEM_callocN<MaskSpline>("new mask spline");
416
417 BLI_addtail(&masklay->splines, spline);
418
419 /* spline shall have one point at least */
420 spline->points = MEM_callocN<MaskSplinePoint>("new mask spline point");
421 spline->tot_point = 1;
422
423 /* cyclic shapes are more usually used */
424 /* Disable because its not so nice for drawing. could be done differently. */
425#if 0
426 spline->flag |= MASK_SPLINE_CYCLIC;
427#endif
428
430
432
433 return spline;
434}
435
437{
438 if (BLI_remlink_safe(&mask_layer->splines, spline) == false) {
439 return false;
440 }
441
442 BKE_mask_spline_free(spline);
443
444 return true;
445}
446
448{
449 const int tot_uw = point->tot_uw;
450 const int tot_uw_half = tot_uw / 2;
451
452 float co_tmp[2];
453
454 /* swap handles */
455 copy_v2_v2(co_tmp, point->bezt.vec[0]);
456 copy_v2_v2(point->bezt.vec[0], point->bezt.vec[2]);
457 copy_v2_v2(point->bezt.vec[2], co_tmp);
458 /* in this case the flags are unlikely to be different but swap anyway */
459 std::swap(point->bezt.f1, point->bezt.f3);
460 std::swap(point->bezt.h1, point->bezt.h2);
461
462 /* swap UW's */
463 if (tot_uw > 1) {
464 /* count */
465 for (int i = 0; i < tot_uw_half; i++) {
466 MaskSplinePointUW *uw_a = &point->uw[i];
467 MaskSplinePointUW *uw_b = &point->uw[tot_uw - (i + 1)];
468 std::swap(*uw_a, *uw_b);
469 }
470 }
471
472 for (int i = 0; i < tot_uw; i++) {
473 MaskSplinePointUW *uw = &point->uw[i];
474 uw->u = 1.0f - uw->u;
475 }
476}
477
479{
480 const int tot_point = spline->tot_point;
481 const int tot_point_half = tot_point / 2;
482 int i, i_prev;
483
484 if (tot_point < 2) {
485 return;
486 }
487
488 /* count */
489 for (i = 0; i < tot_point_half; i++) {
490 MaskSplinePoint *point_a = &spline->points[i];
491 MaskSplinePoint *point_b = &spline->points[tot_point - (i + 1)];
492 std::swap(*point_a, *point_b);
493 }
494
495 /* correct UW's */
496 i_prev = tot_point - 1;
497 for (i = 0; i < tot_point; i++) {
498
500
501 std::swap(spline->points[i].uw, spline->points[i_prev].uw);
502 std::swap(spline->points[i].tot_uw, spline->points[i_prev].tot_uw);
503
504 i_prev = i;
505 }
506
507 /* correct animation */
508 if (masklay->splines_shapes.first) {
509 const int spline_index = BKE_mask_layer_shape_spline_to_index(masklay, spline);
510
511 LISTBASE_FOREACH (MaskLayerShape *, masklay_shape, &masklay->splines_shapes) {
512 MaskLayerShapeElem *fp_arr = (MaskLayerShapeElem *)masklay_shape->data;
513
514 for (i = 0; i < tot_point_half; i++) {
515 MaskLayerShapeElem *fp_a = &fp_arr[spline_index + (i)];
516 MaskLayerShapeElem *fp_b = &fp_arr[spline_index + (tot_point - (i + 1))];
517 std::swap(*fp_a, *fp_b);
518 }
519 }
520 }
521}
522
524 MaskSplinePoint *point,
525 float start_u,
526 const float co[2],
527 const eMaskSign sign)
528{
529 const float proj_eps = 1e-3;
530 const float proj_eps_sq = proj_eps * proj_eps;
531 const int N = 1000;
532 float u = -1.0f, du = 1.0f / N, u1 = start_u, u2 = start_u;
533 float ang = -1.0f;
534
535 BLI_assert(abs(sign) <= 1); /* (-1, 0, 1) */
536
537 while (u1 > 0.0f || u2 < 1.0f) {
538 float n1[2], n2[2], co1[2], co2[2];
539 float v1[2], v2[2];
540 float ang1, ang2;
541
542 if (u1 >= 0.0f) {
543 BKE_mask_point_segment_co(spline, point, u1, co1);
544 BKE_mask_point_normal(spline, point, u1, n1);
545 sub_v2_v2v2(v1, co, co1);
546
547 if ((sign == MASK_PROJ_ANY) || ((sign == MASK_PROJ_NEG) && (dot_v2v2(v1, n1) <= 0.0f)) ||
548 ((sign == MASK_PROJ_POS) && (dot_v2v2(v1, n1) >= 0.0f)))
549 {
550
551 if (len_squared_v2(v1) > proj_eps_sq) {
552 ang1 = angle_v2v2(v1, n1);
553 if (ang1 > float(M_PI_2)) {
554 ang1 = float(M_PI) - ang1;
555 }
556
557 if (ang < 0.0f || ang1 < ang) {
558 ang = ang1;
559 u = u1;
560 }
561 }
562 else {
563 u = u1;
564 break;
565 }
566 }
567 }
568
569 if (u2 <= 1.0f) {
570 BKE_mask_point_segment_co(spline, point, u2, co2);
571 BKE_mask_point_normal(spline, point, u2, n2);
572 sub_v2_v2v2(v2, co, co2);
573
574 if ((sign == MASK_PROJ_ANY) || ((sign == MASK_PROJ_NEG) && (dot_v2v2(v2, n2) <= 0.0f)) ||
575 ((sign == MASK_PROJ_POS) && (dot_v2v2(v2, n2) >= 0.0f)))
576 {
577
578 if (len_squared_v2(v2) > proj_eps_sq) {
579 ang2 = angle_v2v2(v2, n2);
580 if (ang2 > float(M_PI_2)) {
581 ang2 = float(M_PI) - ang2;
582 }
583
584 if (ang2 < ang) {
585 ang = ang2;
586 u = u2;
587 }
588 }
589 else {
590 u = u2;
591 break;
592 }
593 }
594 }
595
596 u1 -= du;
597 u2 += du;
598 }
599
600 return u;
601}
602
603/* point */
604
606{
607 const BezTriple *bezt = &point->bezt;
608
609 if (bezt->h1 == bezt->h2 && bezt->h1 == HD_ALIGN) {
611 }
612
614}
615
617 eMaskWhichHandle which_handle,
618 float r_handle[2])
619{
620 const BezTriple *bezt = &point->bezt;
621
622 if (which_handle == MASK_WHICH_HANDLE_STICK) {
623 float vec[2];
624
625 sub_v2_v2v2(vec, bezt->vec[0], bezt->vec[1]);
626
627 r_handle[0] = (bezt->vec[1][0] + vec[1]);
628 r_handle[1] = (bezt->vec[1][1] - vec[0]);
629 }
630 else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
631 copy_v2_v2(r_handle, bezt->vec[0]);
632 }
633 else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
634 copy_v2_v2(r_handle, bezt->vec[2]);
635 }
636 else {
637 BLI_assert_msg(0, "Unknown handle passed to BKE_mask_point_handle");
638 }
639}
640
642 eMaskWhichHandle which_handle,
643 float loc[2],
644 bool keep_direction,
645 float orig_handle[2],
646 float orig_vec[3][3])
647{
648 BezTriple *bezt = &point->bezt;
649
650 if (which_handle == MASK_WHICH_HANDLE_STICK) {
651 float v1[2], v2[2], vec[2];
652 if (keep_direction) {
653 sub_v2_v2v2(v1, loc, orig_vec[1]);
654 sub_v2_v2v2(v2, orig_handle, orig_vec[1]);
655
656 project_v2_v2v2(vec, v1, v2);
657
658 if (dot_v2v2(v2, vec) > 0) {
659 float len = len_v2(vec);
660
661 sub_v2_v2v2(v1, orig_vec[0], orig_vec[1]);
662
663 mul_v2_fl(v1, len / len_v2(v1));
664
665 add_v2_v2v2(bezt->vec[0], bezt->vec[1], v1);
666 sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v1);
667 }
668 else {
669 copy_v3_v3(bezt->vec[0], bezt->vec[1]);
670 copy_v3_v3(bezt->vec[2], bezt->vec[1]);
671 }
672 }
673 else {
674 sub_v2_v2v2(v1, loc, bezt->vec[1]);
675
676 v2[0] = -v1[1];
677 v2[1] = v1[0];
678
679 add_v2_v2v2(bezt->vec[0], bezt->vec[1], v2);
680 sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v2);
681 }
682 }
683 else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
684 copy_v2_v2(bezt->vec[0], loc);
685 }
686 else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
687 copy_v2_v2(bezt->vec[2], loc);
688 }
689 else {
690 BLI_assert_msg(0, "unknown handle passed to BKE_mask_point_set_handle");
691 }
692}
693
694void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float u, float co[2])
695{
696 MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
697
698 BezTriple *bezt = &point->bezt, *bezt_next;
699
700 bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point);
701
702 if (!bezt_next) {
703 copy_v2_v2(co, bezt->vec[1]);
704 return;
705 }
706
708 co, bezt->vec[1], bezt->vec[2], bezt_next->vec[0], bezt_next->vec[1], u);
709}
710
711BLI_INLINE void orthogonal_direction_get(const float vec[2], float result[2])
712{
713 result[0] = -vec[1];
714 result[1] = vec[0];
716}
717
718void BKE_mask_point_normal(MaskSpline *spline, MaskSplinePoint *point, float u, float n[2])
719{
720 /* TODO(sergey): This function will re-calculate loads of stuff again and again
721 * when differentiating feather points. This might be easily cached
722 * in the callee function for this case. */
723
724 MaskSplinePoint *point_prev, *point_next;
725
726 /* TODO(sergey): This actually depends on a resolution. */
727 const float du = 0.05f;
728
729 BKE_mask_get_handle_point_adjacent(spline, point, &point_prev, &point_next);
730
731 if (u - du < 0.0f && point_prev == nullptr) {
732 float co[2], dir[2];
733 BKE_mask_point_segment_co(spline, point, u + du, co);
734 sub_v2_v2v2(dir, co, point->bezt.vec[1]);
736 }
737 else if (u + du > 1.0f && point_next == nullptr) {
738 float co[2], dir[2];
739 BKE_mask_point_segment_co(spline, point, u - du, co);
740 sub_v2_v2v2(dir, point->bezt.vec[1], co);
742 }
743 else {
744 float prev_co[2], next_co[2], co[2];
745 float dir1[2], dir2[2], dir[2];
746
747 if (u - du < 0.0f) {
748 BKE_mask_point_segment_co(spline, point_prev, 1.0f + (u - du), prev_co);
749 }
750 else {
751 BKE_mask_point_segment_co(spline, point, u - du, prev_co);
752 }
753
754 BKE_mask_point_segment_co(spline, point, u, co);
755
756 if (u + du > 1.0f) {
757 BKE_mask_point_segment_co(spline, point_next, u + du - 1.0f, next_co);
758 }
759 else {
760 BKE_mask_point_segment_co(spline, point, u + du, next_co);
761 }
762
763 sub_v2_v2v2(dir1, co, prev_co);
764 sub_v2_v2v2(dir2, next_co, co);
765
766 normalize_v2(dir1);
767 normalize_v2(dir2);
768 add_v2_v2v2(dir, dir1, dir2);
769
771 }
772}
773
774static float mask_point_interp_weight(BezTriple *bezt, BezTriple *bezt_next, const float u)
775{
776 return (bezt->weight * (1.0f - u)) + (bezt_next->weight * u);
777}
778
779float BKE_mask_point_weight_scalar(MaskSpline *spline, MaskSplinePoint *point, const float u)
780{
781 MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
782 BezTriple *bezt = &point->bezt, *bezt_next;
783
784 bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point);
785
786 if (!bezt_next) {
787 return bezt->weight;
788 }
789 if (u <= 0.0f) {
790 return bezt->weight;
791 }
792 if (u >= 1.0f) {
793 return bezt_next->weight;
794 }
795
796 return mask_point_interp_weight(bezt, bezt_next, u);
797}
798
799float BKE_mask_point_weight(MaskSpline *spline, MaskSplinePoint *point, const float u)
800{
801 MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
802 BezTriple *bezt = &point->bezt, *bezt_next;
803
804 bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point);
805
806 if (!bezt_next) {
807 return bezt->weight;
808 }
809 if (u <= 0.0f) {
810 return bezt->weight;
811 }
812 if (u >= 1.0f) {
813 return bezt_next->weight;
814 }
815
816 float cur_u = 0.0f, cur_w = 0.0f, next_u = 0.0f, next_w = 0.0f, fac; /* Quite warnings */
817
818 for (int i = 0; i <= point->tot_uw; i++) {
819 if (i == 0) {
820 cur_u = 0.0f;
821 cur_w = 1.0f; /* mask_point_interp_weight will scale it */
822 }
823 else {
824 cur_u = point->uw[i - 1].u;
825 cur_w = point->uw[i - 1].w;
826 }
827
828 if (i == point->tot_uw) {
829 next_u = 1.0f;
830 next_w = 1.0f; /* mask_point_interp_weight will scale it */
831 }
832 else {
833 next_u = point->uw[i].u;
834 next_w = point->uw[i].w;
835 }
836
837 if (u >= cur_u && u <= next_u) {
838 break;
839 }
840 }
841
842 fac = (u - cur_u) / (next_u - cur_u);
843
844 cur_w *= mask_point_interp_weight(bezt, bezt_next, cur_u);
845 next_w *= mask_point_interp_weight(bezt, bezt_next, next_u);
846
847 if (spline->weight_interp == MASK_SPLINE_INTERP_EASE) {
848 return cur_w + (next_w - cur_w) * (3.0f * fac * fac - 2.0f * fac * fac * fac);
849 }
850
851 return (1.0f - fac) * cur_w + fac * next_w;
852}
853
855{
856 if (point->tot_uw > 1) {
857 int idx = uw - point->uw;
858
859 if (idx > 0 && point->uw[idx - 1].u > uw->u) {
860 while (idx > 0 && point->uw[idx - 1].u > point->uw[idx].u) {
861 std::swap(point->uw[idx - 1], point->uw[idx]);
862 idx--;
863 }
864 }
865
866 if (idx < point->tot_uw - 1 && point->uw[idx + 1].u < uw->u) {
867 while (idx < point->tot_uw - 1 && point->uw[idx + 1].u < point->uw[idx].u) {
868 std::swap(point->uw[idx + 1], point->uw[idx]);
869 idx++;
870 }
871 }
872
873 return &point->uw[idx];
874 }
875
876 return uw;
877}
878
879void BKE_mask_point_add_uw(MaskSplinePoint *point, float u, float w)
880{
881 if (!point->uw) {
882 point->uw = MEM_callocN<MaskSplinePointUW>("mask point uw");
883 }
884 else {
885 point->uw = static_cast<MaskSplinePointUW *>(
886 MEM_reallocN(point->uw, (point->tot_uw + 1) * sizeof(*point->uw)));
887 }
888
889 point->uw[point->tot_uw].u = u;
890 point->uw[point->tot_uw].w = w;
891 point->uw[point->tot_uw].flag = 0;
892
893 point->tot_uw++;
894
895 BKE_mask_point_sort_uw(point, &point->uw[point->tot_uw - 1]);
896}
897
898void BKE_mask_point_select_set(MaskSplinePoint *point, const bool do_select)
899{
900 if (do_select) {
901 MASKPOINT_SEL_ALL(point);
902 }
903 else {
904 MASKPOINT_DESEL_ALL(point);
905 }
906
907 for (int i = 0; i < point->tot_uw; i++) {
908 if (do_select) {
909 point->uw[i].flag |= SELECT;
910 }
911 else {
912 point->uw[i].flag &= ~SELECT;
913 }
914 }
915}
916
918 const eMaskWhichHandle which_handle,
919 const bool do_select)
920{
921 if (do_select) {
923 point->bezt.f1 |= SELECT;
924 point->bezt.f3 |= SELECT;
925 }
926 else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
927 point->bezt.f1 |= SELECT;
928 }
929 else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
930 point->bezt.f3 |= SELECT;
931 }
932 else {
933 BLI_assert_msg(0, "Wrong which_handle passed to BKE_mask_point_select_set_handle");
934 }
935 }
936 else {
938 point->bezt.f1 &= ~SELECT;
939 point->bezt.f3 &= ~SELECT;
940 }
941 else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
942 point->bezt.f1 &= ~SELECT;
943 }
944 else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
945 point->bezt.f3 &= ~SELECT;
946 }
947 else {
948 BLI_assert_msg(0, "Wrong which_handle passed to BKE_mask_point_select_set_handle");
949 }
950 }
951}
952
953/* only mask block itself */
954static Mask *mask_alloc(Main *bmain, const char *name)
955{
956 Mask *mask = static_cast<Mask *>(BKE_libblock_alloc(bmain, ID_MSK, name, 0));
957
959
960 return mask;
961}
962
963Mask *BKE_mask_new(Main *bmain, const char *name)
964{
965 Mask *mask;
966 char mask_name[MAX_ID_NAME - 2];
967
968 STRNCPY_UTF8(mask_name, (name && name[0]) ? name : DATA_("Mask"));
969
970 mask = mask_alloc(bmain, mask_name);
971
972 /* arbitrary defaults */
973 mask->sfra = 1;
974 mask->efra = 100;
975
977
978 return mask;
979}
980
982{
983 if (point->uw) {
984 MEM_freeN(point->uw);
985 }
986}
987
989{
990 int i = 0;
991
992 for (i = 0; i < spline->tot_point; i++) {
993 MaskSplinePoint *point;
994 point = &spline->points[i];
995 BKE_mask_point_free(point);
996
997 if (spline->points_deform) {
998 point = &spline->points_deform[i];
999 BKE_mask_point_free(point);
1000 }
1001 }
1002
1003 MEM_freeN(spline->points);
1004
1005 if (spline->points_deform) {
1006 MEM_freeN(spline->points_deform);
1007 }
1008
1009 MEM_freeN(spline);
1010}
1011
1013{
1014 MaskSpline *spline = static_cast<MaskSpline *>(splines->first);
1015 while (spline) {
1016 MaskSpline *next_spline = spline->next;
1017
1018 BLI_remlink(splines, spline);
1019 BKE_mask_spline_free(spline);
1020
1021 spline = next_spline;
1022 }
1023}
1024
1025static MaskSplinePoint *mask_spline_points_copy(const MaskSplinePoint *points, int tot_point)
1026{
1027 MaskSplinePoint *npoints = static_cast<MaskSplinePoint *>(MEM_dupallocN(points));
1028
1029 for (int i = 0; i < tot_point; i++) {
1030 MaskSplinePoint *point = &npoints[i];
1031
1032 if (point->uw) {
1033 point->uw = static_cast<MaskSplinePointUW *>(MEM_dupallocN(point->uw));
1034 }
1035 }
1036
1037 return npoints;
1038}
1039
1041{
1042 MaskSpline *nspline = MEM_callocN<MaskSpline>("new spline");
1043
1044 *nspline = *spline;
1045
1046 nspline->points_deform = nullptr;
1047 nspline->points = mask_spline_points_copy(spline->points, spline->tot_point);
1048
1049 if (spline->points_deform) {
1050 nspline->points_deform = mask_spline_points_copy(spline->points_deform, spline->tot_point);
1051 }
1052
1053 return nspline;
1054}
1055
1057{
1058 MaskLayerShape *masklay_shape;
1059 int tot_vert = BKE_mask_layer_shape_totvert(masklay);
1060
1061 masklay_shape = MEM_callocN<MaskLayerShape>(__func__);
1062 masklay_shape->frame = frame;
1063 masklay_shape->tot_vert = tot_vert;
1064 masklay_shape->data = MEM_calloc_arrayN<float>(tot_vert * MASK_OBJECT_SHAPE_ELEM_SIZE, __func__);
1065
1066 return masklay_shape;
1067}
1068
1070{
1071 if (masklay_shape->data) {
1072 MEM_freeN(masklay_shape->data);
1073 }
1074
1075 MEM_freeN(masklay_shape);
1076}
1077
1079{
1080 MaskLayerShape *masklay_shape;
1081
1082 /* free animation data */
1083 masklay_shape = static_cast<MaskLayerShape *>(masklay->splines_shapes.first);
1084 while (masklay_shape) {
1085 MaskLayerShape *next_masklay_shape = masklay_shape->next;
1086
1087 BLI_remlink(&masklay->splines_shapes, masklay_shape);
1088 BKE_mask_layer_shape_free(masklay_shape);
1089
1090 masklay_shape = next_masklay_shape;
1091 }
1092}
1093
1095{
1096 /* free splines */
1098
1099 /* free animation data */
1101
1102 MEM_freeN(masklay);
1103}
1104
1106{
1107 MaskLayer *masklay = static_cast<MaskLayer *>(masklayers->first);
1108
1109 while (masklay) {
1110 MaskLayer *masklay_next = masklay->next;
1111
1112 BLI_remlink(masklayers, masklay);
1113 BKE_mask_layer_free(masklay);
1114
1115 masklay = masklay_next;
1116 }
1117}
1118
1119void BKE_mask_coord_from_frame(float r_co[2], const float co[2], const float frame_size[2])
1120{
1121 if (frame_size[0] == frame_size[1]) {
1122 r_co[0] = co[0];
1123 r_co[1] = co[1];
1124 }
1125 else if (frame_size[0] < frame_size[1]) {
1126 r_co[0] = ((co[0] - 0.5f) * (frame_size[0] / frame_size[1])) + 0.5f;
1127 r_co[1] = co[1];
1128 }
1129 else { /* (frame_size[0] > frame_size[1]) */
1130 r_co[0] = co[0];
1131 r_co[1] = ((co[1] - 0.5f) * (frame_size[1] / frame_size[0])) + 0.5f;
1132 }
1133}
1134
1136 MovieClipUser *user,
1137 float r_co[2],
1138 const float co[2])
1139{
1140 float aspx, aspy;
1141 float frame_size[2];
1142
1143 /* scaling for the clip */
1144 BKE_movieclip_get_size_fl(clip, user, frame_size);
1145 BKE_movieclip_get_aspect(clip, &aspx, &aspy);
1146
1147 frame_size[1] *= (aspy / aspx);
1148
1149 BKE_mask_coord_from_frame(r_co, co, frame_size);
1150}
1151
1152void BKE_mask_coord_from_image(Image *image, ImageUser *iuser, float r_co[2], const float co[2])
1153{
1154 float aspx, aspy;
1155 float frame_size[2];
1156
1157 BKE_image_get_size_fl(image, iuser, frame_size);
1158 BKE_image_get_aspect(image, &aspx, &aspy);
1159
1160 frame_size[1] *= (aspy / aspx);
1161
1162 BKE_mask_coord_from_frame(r_co, co, frame_size);
1163}
1164
1165void BKE_mask_coord_to_frame(float r_co[2], const float co[2], const float frame_size[2])
1166{
1167 if (frame_size[0] == frame_size[1]) {
1168 r_co[0] = co[0];
1169 r_co[1] = co[1];
1170 }
1171 else if (frame_size[0] < frame_size[1]) {
1172 r_co[0] = ((co[0] - 0.5f) / (frame_size[0] / frame_size[1])) + 0.5f;
1173 r_co[1] = co[1];
1174 }
1175 else { /* (frame_size[0] > frame_size[1]) */
1176 r_co[0] = co[0];
1177 r_co[1] = ((co[1] - 0.5f) / (frame_size[1] / frame_size[0])) + 0.5f;
1178 }
1179}
1180
1182 MovieClipUser *user,
1183 float r_co[2],
1184 const float co[2])
1185{
1186 float aspx, aspy;
1187 float frame_size[2];
1188
1189 /* scaling for the clip */
1190 BKE_movieclip_get_size_fl(clip, user, frame_size);
1191 BKE_movieclip_get_aspect(clip, &aspx, &aspy);
1192
1193 frame_size[1] *= (aspy / aspx);
1194
1195 BKE_mask_coord_to_frame(r_co, co, frame_size);
1196}
1197
1198void BKE_mask_coord_to_image(Image *image, ImageUser *iuser, float r_co[2], const float co[2])
1199{
1200 float aspx, aspy;
1201 float frame_size[2];
1202
1203 /* scaling for the clip */
1204 BKE_image_get_size_fl(image, iuser, frame_size);
1205 BKE_image_get_aspect(image, &aspx, &aspy);
1206
1207 frame_size[1] *= (aspy / aspx);
1208
1209 BKE_mask_coord_to_frame(r_co, co, frame_size);
1210}
1211
1213 float ctime,
1214 float parent_matrix[3][3])
1215{
1216 MaskParent *parent = &point->parent;
1217
1218 unit_m3(parent_matrix);
1219
1220 if (!parent) {
1221 return;
1222 }
1223
1224 if (parent->id_type == ID_MC) {
1225 if (parent->id) {
1226 MovieClip *clip = (MovieClip *)parent->id;
1227 MovieTracking *tracking = (MovieTracking *)&clip->tracking;
1229
1230 if (ob) {
1232 float clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
1233 BKE_movieclip_user_set_frame(&user, ctime);
1234
1235 if (parent->type == MASK_PARENT_POINT_TRACK) {
1237 parent->sub_parent);
1238
1239 if (track) {
1240 float marker_position[2], parent_co[2];
1241 BKE_tracking_marker_get_subframe_position(track, clip_framenr, marker_position);
1242 BKE_mask_coord_from_movieclip(clip, &user, parent_co, marker_position);
1243 sub_v2_v2v2(parent_matrix[2], parent_co, parent->parent_orig);
1244 }
1245 }
1246 else /* if (parent->type == MASK_PARENT_PLANE_TRACK) */ {
1248 ob, parent->sub_parent);
1249
1250 if (plane_track) {
1251 float corners[4][2];
1252 float aspx, aspy;
1253 float frame_size[2], H[3][3], mask_from_clip_matrix[3][3], mask_to_clip_matrix[3][3];
1254
1255 BKE_tracking_plane_marker_get_subframe_corners(plane_track, ctime, corners);
1257
1258 unit_m3(mask_from_clip_matrix);
1259
1260 BKE_movieclip_get_size_fl(clip, &user, frame_size);
1261 BKE_movieclip_get_aspect(clip, &aspx, &aspy);
1262
1263 frame_size[1] *= (aspy / aspx);
1264 if (frame_size[0] == frame_size[1]) {
1265 /* pass */
1266 }
1267 else if (frame_size[0] < frame_size[1]) {
1268 mask_from_clip_matrix[0][0] = frame_size[1] / frame_size[0];
1269 mask_from_clip_matrix[2][0] = -0.5f * (frame_size[1] / frame_size[0]) + 0.5f;
1270 }
1271 else { /* (frame_size[0] > frame_size[1]) */
1272 mask_from_clip_matrix[1][1] = frame_size[1] / frame_size[0];
1273 mask_from_clip_matrix[2][1] = -0.5f * (frame_size[1] / frame_size[0]) + 0.5f;
1274 }
1275
1276 invert_m3_m3(mask_to_clip_matrix, mask_from_clip_matrix);
1277 mul_m3_series(parent_matrix, mask_from_clip_matrix, H, mask_to_clip_matrix);
1278 }
1279 }
1280 }
1281 }
1282 }
1283}
1284
1286 MaskSplinePoint *point_prev,
1287 MaskSplinePoint *point_next)
1288{
1289 BezTriple *bezt = &point->bezt;
1290 BezTriple *bezt_prev = nullptr, *bezt_next = nullptr;
1291 // int handle_type = bezt->h1;
1292
1293 if (point_prev) {
1294 bezt_prev = &point_prev->bezt;
1295 }
1296
1297 if (point_next) {
1298 bezt_next = &point_next->bezt;
1299 }
1300
1301#if 1
1302 if (bezt_prev || bezt_next) {
1303 BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, false, 0);
1304 }
1305#else
1306 if (handle_type == HD_VECT) {
1307 BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, 0, 0);
1308 }
1309 else if (handle_type == HD_AUTO) {
1310 BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, 0, 0);
1311 }
1312 else if (ELEM(handle_type, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
1313 float v1[3], v2[3];
1314 float vec[3], h[3];
1315
1316 sub_v3_v3v3(v1, bezt->vec[0], bezt->vec[1]);
1317 sub_v3_v3v3(v2, bezt->vec[2], bezt->vec[1]);
1318 add_v3_v3v3(vec, v1, v2);
1319
1320 if (len_squared_v3(vec) > (1e-3f * 1e-3f)) {
1321 h[0] = vec[1];
1322 h[1] = -vec[0];
1323 h[2] = 0.0f;
1324 }
1325 else {
1326 copy_v3_v3(h, v1);
1327 }
1328
1329 add_v3_v3v3(bezt->vec[0], bezt->vec[1], h);
1330 sub_v3_v3v3(bezt->vec[2], bezt->vec[1], h);
1331 }
1332#endif
1333}
1334
1336 MaskSplinePoint *point,
1337 MaskSplinePoint **r_point_prev,
1338 MaskSplinePoint **r_point_next)
1339{
1340 /* TODO: could avoid calling this at such low level. */
1341 MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
1342
1343 *r_point_prev = mask_spline_point_prev(spline, points_array, point);
1344 *r_point_next = mask_spline_point_next(spline, points_array, point);
1345}
1346
1348{
1349 float tvec_a[2], tvec_b[2];
1350
1351 MaskSplinePoint *point_prev, *point_next;
1352
1353 BKE_mask_get_handle_point_adjacent(spline, point, &point_prev, &point_next);
1354
1355 if (point_prev) {
1356 sub_v2_v2v2(tvec_a, point->bezt.vec[1], point_prev->bezt.vec[1]);
1357 normalize_v2(tvec_a);
1358 }
1359 else {
1360 zero_v2(tvec_a);
1361 }
1362
1363 if (point_next) {
1364 sub_v2_v2v2(tvec_b, point_next->bezt.vec[1], point->bezt.vec[1]);
1365 normalize_v2(tvec_b);
1366 }
1367 else {
1368 zero_v2(tvec_b);
1369 }
1370
1371 add_v2_v2v2(t, tvec_a, tvec_b);
1372 normalize_v2(t);
1373}
1374
1376{
1377 MaskSplinePoint *point_prev, *point_next;
1378
1379 BKE_mask_get_handle_point_adjacent(spline, point, &point_prev, &point_next);
1380
1381 mask_calc_point_handle(point, point_prev, point_next);
1382}
1383
1385 MaskSplinePoint *point,
1386 const float u)
1387{
1388 /* TODO: make this interpolate between siblings - not always midpoint! */
1389 int length_tot = 0;
1390 float length_average = 0.0f;
1391 float weight_average = 0.0f;
1392
1393 MaskSplinePoint *point_prev, *point_next;
1394
1395 BLI_assert(u >= 0.0f && u <= 1.0f);
1396
1397 BKE_mask_get_handle_point_adjacent(spline, point, &point_prev, &point_next);
1398
1399 if (point_prev && point_next) {
1400 length_average = ((len_v2v2(point_prev->bezt.vec[0], point_prev->bezt.vec[1]) * (1.0f - u)) +
1401 (len_v2v2(point_next->bezt.vec[2], point_next->bezt.vec[1]) * u));
1402
1403 weight_average = (point_prev->bezt.weight * (1.0f - u) + point_next->bezt.weight * u);
1404 length_tot = 1;
1405 }
1406 else {
1407 if (point_prev) {
1408 length_average += len_v2v2(point_prev->bezt.vec[0], point_prev->bezt.vec[1]);
1409 weight_average += point_prev->bezt.weight;
1410 length_tot++;
1411 }
1412
1413 if (point_next) {
1414 length_average += len_v2v2(point_next->bezt.vec[2], point_next->bezt.vec[1]);
1415 weight_average += point_next->bezt.weight;
1416 length_tot++;
1417 }
1418 }
1419
1420 if (length_tot) {
1421 length_average /= float(length_tot);
1422 weight_average /= float(length_tot);
1423
1424 dist_ensure_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average);
1425 dist_ensure_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average);
1426 point->bezt.weight = weight_average;
1427 }
1428}
1429
1431 MaskSplinePoint *point,
1432 const bool do_recalc_length)
1433{
1434 MaskSplinePoint *point_prev, *point_next;
1435 const char h_back[2] = {point->bezt.h1, point->bezt.h2};
1436 const float length_average = (do_recalc_length) ?
1437 0.0f /* dummy value */ :
1438 (len_v3v3(point->bezt.vec[0], point->bezt.vec[1]) +
1439 len_v3v3(point->bezt.vec[1], point->bezt.vec[2])) /
1440 2.0f;
1441
1442 BKE_mask_get_handle_point_adjacent(spline, point, &point_prev, &point_next);
1443
1444 point->bezt.h1 = HD_AUTO;
1445 point->bezt.h2 = HD_AUTO;
1446 mask_calc_point_handle(point, point_prev, point_next);
1447
1448 point->bezt.h1 = h_back[0];
1449 point->bezt.h2 = h_back[1];
1450
1451 /* preserve length by applying it back */
1452 if (do_recalc_length == false) {
1453 dist_ensure_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average);
1454 dist_ensure_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average);
1455 }
1456}
1457
1459{
1460 LISTBASE_FOREACH (MaskSpline *, spline, &masklay->splines) {
1461 for (int i = 0; i < spline->tot_point; i++) {
1462 BKE_mask_calc_handle_point(spline, &spline->points[i]);
1463 }
1464 }
1465}
1466
1468{
1469 int allocated_points = (MEM_allocN_len(spline->points_deform) / sizeof(*spline->points_deform));
1470 // printf("SPLINE ALLOC %p %d\n", spline->points_deform, allocated_points);
1471
1472 if (spline->points_deform == nullptr || allocated_points != spline->tot_point) {
1473 // printf("alloc new deform spline\n");
1474
1475 if (spline->points_deform) {
1476 for (int i = 0; i < allocated_points; i++) {
1477 MaskSplinePoint *point = &spline->points_deform[i];
1478 BKE_mask_point_free(point);
1479 }
1480
1481 MEM_freeN(spline->points_deform);
1482 }
1483
1484 spline->points_deform = MEM_calloc_arrayN<MaskSplinePoint>(spline->tot_point, __func__);
1485 }
1486 else {
1487 // printf("alloc spline done\n");
1488 }
1489}
1490
1491void BKE_mask_layer_evaluate(MaskLayer *masklay, const float ctime, const bool do_newframe)
1492{
1493 /* Animation if available. */
1494 if (do_newframe) {
1495 BKE_mask_layer_evaluate_animation(masklay, ctime);
1496 }
1497 /* Update deform. */
1498 BKE_mask_layer_evaluate_deform(masklay, ctime);
1499}
1500
1501void BKE_mask_evaluate(Mask *mask, const float ctime, const bool do_newframe)
1502{
1503 LISTBASE_FOREACH (MaskLayer *, masklay, &mask->masklayers) {
1504 BKE_mask_layer_evaluate(masklay, ctime, do_newframe);
1505 }
1506}
1507
1509{
1510 parent->id_type = ID_MC;
1511}
1512
1513/* *** animation/shape-key implementation ***
1514 * BKE_mask_layer_shape_XXX */
1515
1517{
1518 int tot = 0;
1519
1520 LISTBASE_FOREACH (MaskSpline *, spline, &masklay->splines) {
1521 tot += spline->tot_point;
1522 }
1523
1524 return tot;
1525}
1526
1529{
1530 copy_v2_v2(&fp[0], bezt->vec[0]);
1531 copy_v2_v2(&fp[2], bezt->vec[1]);
1532 copy_v2_v2(&fp[4], bezt->vec[2]);
1533 fp[6] = bezt->weight;
1534 fp[7] = bezt->radius;
1535}
1536
1538 const float fp[MASK_OBJECT_SHAPE_ELEM_SIZE])
1539{
1540 copy_v2_v2(bezt->vec[0], &fp[0]);
1541 copy_v2_v2(bezt->vec[1], &fp[2]);
1542 copy_v2_v2(bezt->vec[2], &fp[4]);
1543 bezt->weight = fp[6];
1544 bezt->radius = fp[7];
1545}
1546
1548{
1549 int tot = BKE_mask_layer_shape_totvert(masklay);
1550
1551 if (masklay_shape->tot_vert == tot) {
1552 float *fp = masklay_shape->data;
1553
1554 LISTBASE_FOREACH (MaskSpline *, spline, &masklay->splines) {
1555 for (int i = 0; i < spline->tot_point; i++) {
1556 mask_layer_shape_from_mask_point(&spline->points[i].bezt, fp);
1558 }
1559 }
1560 }
1561 else {
1562 CLOG_ERROR(&LOG,
1563 "vert mismatch %d != %d (frame %d)",
1564 masklay_shape->tot_vert,
1565 tot,
1566 masklay_shape->frame);
1567 }
1568}
1569
1571{
1572 int tot = BKE_mask_layer_shape_totvert(masklay);
1573
1574 if (masklay_shape->tot_vert == tot) {
1575 float *fp = masklay_shape->data;
1576
1577 LISTBASE_FOREACH (MaskSpline *, spline, &masklay->splines) {
1578 for (int i = 0; i < spline->tot_point; i++) {
1579 mask_layer_shape_to_mask_point(&spline->points[i].bezt, fp);
1581 }
1582 }
1583 }
1584 else {
1585 CLOG_ERROR(&LOG,
1586 "vert mismatch %d != %d (frame %d)",
1587 masklay_shape->tot_vert,
1588 tot,
1589 masklay_shape->frame);
1590 }
1591}
1592
1594 float target[2], const float a[2], const float b[2], const float t, const float s)
1595{
1596 target[0] = s * a[0] + t * b[0];
1597 target[1] = s * a[1] + t * b[1];
1598}
1599
1601 MaskLayerShape *masklay_shape_a,
1602 MaskLayerShape *masklay_shape_b,
1603 const float fac)
1604{
1605 int tot = BKE_mask_layer_shape_totvert(masklay);
1606 if (masklay_shape_a->tot_vert == tot && masklay_shape_b->tot_vert == tot) {
1607 const float *fp_a = masklay_shape_a->data;
1608 const float *fp_b = masklay_shape_b->data;
1609 const float ifac = 1.0f - fac;
1610
1611 LISTBASE_FOREACH (MaskSpline *, spline, &masklay->splines) {
1612 for (int i = 0; i < spline->tot_point; i++) {
1613 BezTriple *bezt = &spline->points[i].bezt;
1614 /* *** BKE_mask_layer_shape_from_mask - swapped *** */
1615 interp_v2_v2v2_flfl(bezt->vec[0], fp_a, fp_b, fac, ifac);
1616 fp_a += 2;
1617 fp_b += 2;
1618 interp_v2_v2v2_flfl(bezt->vec[1], fp_a, fp_b, fac, ifac);
1619 fp_a += 2;
1620 fp_b += 2;
1621 interp_v2_v2v2_flfl(bezt->vec[2], fp_a, fp_b, fac, ifac);
1622 fp_a += 2;
1623 fp_b += 2;
1624 bezt->weight = (fp_a[0] * ifac) + (fp_b[0] * fac);
1625 bezt->radius = (fp_a[1] * ifac) + (fp_b[1] * fac);
1626 fp_a += 2;
1627 fp_b += 2;
1628 }
1629 }
1630 }
1631 else {
1632 CLOG_ERROR(&LOG,
1633 "vert mismatch %d != %d != %d (frame %d - %d)",
1634 masklay_shape_a->tot_vert,
1635 masklay_shape_b->tot_vert,
1636 tot,
1637 masklay_shape_a->frame,
1638 masklay_shape_b->frame);
1639 }
1640}
1641
1643{
1644 LISTBASE_FOREACH (MaskLayerShape *, masklay_shape, &masklay->splines_shapes) {
1645 if (frame == masklay_shape->frame) {
1646 return masklay_shape;
1647 }
1648 if (frame < masklay_shape->frame) {
1649 break;
1650 }
1651 }
1652
1653 return nullptr;
1654}
1655
1657 const float frame,
1658 MaskLayerShape **r_masklay_shape_a,
1659 MaskLayerShape **r_masklay_shape_b)
1660{
1661 MaskLayerShape *masklay_shape;
1662
1663 for (masklay_shape = static_cast<MaskLayerShape *>(masklay->splines_shapes.first); masklay_shape;
1664 masklay_shape = masklay_shape->next)
1665 {
1666 if (frame == masklay_shape->frame) {
1667 *r_masklay_shape_a = masklay_shape;
1668 *r_masklay_shape_b = nullptr;
1669 return 1;
1670 }
1671 if (frame < masklay_shape->frame) {
1672 if (masklay_shape->prev) {
1673 *r_masklay_shape_a = masklay_shape->prev;
1674 *r_masklay_shape_b = masklay_shape;
1675 return 2;
1676 }
1677
1678 *r_masklay_shape_a = masklay_shape;
1679 *r_masklay_shape_b = nullptr;
1680 return 1;
1681 }
1682 }
1683
1684 masklay_shape = static_cast<MaskLayerShape *>(masklay->splines_shapes.last);
1685 if (masklay_shape) {
1686 *r_masklay_shape_a = masklay_shape;
1687 *r_masklay_shape_b = nullptr;
1688 return 1;
1689 }
1690
1691 *r_masklay_shape_a = nullptr;
1692 *r_masklay_shape_b = nullptr;
1693
1694 return 0;
1695}
1696
1698{
1699 MaskLayerShape *masklay_shape;
1700
1701 masklay_shape = BKE_mask_layer_shape_find_frame(masklay, frame);
1702
1703 if (masklay_shape == nullptr) {
1704 masklay_shape = BKE_mask_layer_shape_alloc(masklay, frame);
1705 BLI_addtail(&masklay->splines_shapes, masklay_shape);
1707 }
1708
1709 return masklay_shape;
1710}
1711
1713{
1714 MaskLayerShape *masklay_shape_copy = static_cast<MaskLayerShape *>(MEM_dupallocN(masklay_shape));
1715
1716 if (LIKELY(masklay_shape_copy->data)) {
1717 masklay_shape_copy->data = static_cast<float *>(MEM_dupallocN(masklay_shape_copy->data));
1718 }
1719
1720 return masklay_shape_copy;
1721}
1722
1724{
1725 BLI_remlink(&masklay->splines_shapes, masklay_shape);
1726
1727 BKE_mask_layer_shape_free(masklay_shape);
1728}
1729
1730static int mask_layer_shape_sort_cb(const void *masklay_shape_a_ptr,
1731 const void *masklay_shape_b_ptr)
1732{
1733 const MaskLayerShape *masklay_shape_a = static_cast<const MaskLayerShape *>(masklay_shape_a_ptr);
1734 const MaskLayerShape *masklay_shape_b = static_cast<const MaskLayerShape *>(masklay_shape_b_ptr);
1735
1736 if (masklay_shape_a->frame < masklay_shape_b->frame) {
1737 return -1;
1738 }
1739 if (masklay_shape_a->frame > masklay_shape_b->frame) {
1740 return 1;
1741 }
1742
1743 return 0;
1744}
1745
1750
1752 int index,
1753 MaskSpline **r_masklay_shape,
1754 int *r_index)
1755{
1756 LISTBASE_FOREACH (MaskSpline *, spline, &masklay->splines) {
1757 if (index < spline->tot_point) {
1758 *r_masklay_shape = spline;
1759 *r_index = index;
1760 return true;
1761 }
1762 index -= spline->tot_point;
1763 }
1764
1765 return false;
1766}
1767
1769{
1770 MaskSpline *spline_iter;
1771 int i_abs = 0;
1772 for (spline_iter = static_cast<MaskSpline *>(masklay->splines.first);
1773 spline_iter && spline_iter != spline;
1774 i_abs += spline_iter->tot_point, spline_iter = spline_iter->next)
1775 {
1776 /* pass */
1777 }
1778
1779 return i_abs;
1780}
1781
1782/* basic 2D interpolation functions, could make more comprehensive later */
1783static void interp_weights_uv_v2_calc(float r_uv[2],
1784 const float pt[2],
1785 const float pt_a[2],
1786 const float pt_b[2])
1787{
1788 const float segment_len = len_v2v2(pt_a, pt_b);
1789 if (segment_len == 0.0f) {
1790 r_uv[0] = 1.0f;
1791 r_uv[1] = 0.0f;
1792 return;
1793 }
1794
1795 float pt_on_line[2];
1796 r_uv[0] = closest_to_line_v2(pt_on_line, pt, pt_a, pt_b);
1797
1798 r_uv[1] = (len_v2v2(pt_on_line, pt) / segment_len) *
1799 /* This line only sets the sign. */
1800 ((line_point_side_v2(pt_a, pt_b, pt) < 0.0f) ? -1.0f : 1.0f);
1801}
1802
1803static void interp_weights_uv_v2_apply(const float uv[2],
1804 float r_pt[2],
1805 const float pt_a[2],
1806 const float pt_b[2])
1807{
1808 const float dvec[2] = {pt_b[0] - pt_a[0], pt_b[1] - pt_a[1]};
1809
1810 /* u */
1811 madd_v2_v2v2fl(r_pt, pt_a, dvec, uv[0]);
1812
1813 /* v */
1814 r_pt[0] += -dvec[1] * uv[1];
1815 r_pt[1] += dvec[0] * uv[1];
1816}
1817
1819 int index,
1820 bool do_init,
1821 bool do_init_interpolate)
1822{
1823 /* spline index from masklay */
1824 MaskSpline *spline;
1825 int spline_point_index;
1826
1827 if (BKE_mask_layer_shape_spline_from_index(masklay, index, &spline, &spline_point_index)) {
1828 /* sanity check */
1829 /* The point has already been removed in this array
1830 * so subtract one when comparing with the shapes. */
1831 int tot = BKE_mask_layer_shape_totvert(masklay) - 1;
1832
1833 /* for interpolation */
1834 /* TODO: assumes closed curve for now. */
1835 float uv[3][2]; /* 3x 2D handles */
1836 const int pi_curr = spline_point_index;
1837 const int pi_prev = ((spline_point_index - 1) + spline->tot_point) % spline->tot_point;
1838 const int pi_next = (spline_point_index + 1) % spline->tot_point;
1839
1840 const int index_offset = index - spline_point_index;
1841 // const int pi_curr_abs = index;
1842 const int pi_prev_abs = pi_prev + index_offset;
1843 const int pi_next_abs = pi_next + index_offset;
1844
1845 if (do_init_interpolate) {
1846 for (int i = 0; i < 3; i++) {
1848 spline->points[pi_curr].bezt.vec[i],
1849 spline->points[pi_prev].bezt.vec[i],
1850 spline->points[pi_next].bezt.vec[i]);
1851 }
1852 }
1853
1854 LISTBASE_FOREACH (MaskLayerShape *, masklay_shape, &masklay->splines_shapes) {
1855 if (tot == masklay_shape->tot_vert) {
1856 float *data_resized;
1857
1858 masklay_shape->tot_vert++;
1859 data_resized = MEM_calloc_arrayN<float>(
1860 masklay_shape->tot_vert * MASK_OBJECT_SHAPE_ELEM_SIZE, __func__);
1861 if (index > 0) {
1862 memcpy(data_resized,
1863 masklay_shape->data,
1864 index * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE);
1865 }
1866
1867 if (index != masklay_shape->tot_vert - 1) {
1868 memcpy(&data_resized[(index + 1) * MASK_OBJECT_SHAPE_ELEM_SIZE],
1869 masklay_shape->data + (index * MASK_OBJECT_SHAPE_ELEM_SIZE),
1870 (masklay_shape->tot_vert - (index + 1)) * sizeof(float) *
1872 }
1873
1874 if (do_init) {
1875 float *fp = &data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE];
1876
1877 mask_layer_shape_from_mask_point(&spline->points[spline_point_index].bezt, fp);
1878
1879 if (do_init_interpolate && spline->tot_point > 2) {
1880 for (int i = 0; i < 3; i++) {
1882 uv[i],
1883 &fp[i * 2],
1884 &data_resized[(pi_prev_abs * MASK_OBJECT_SHAPE_ELEM_SIZE) + (i * 2)],
1885 &data_resized[(pi_next_abs * MASK_OBJECT_SHAPE_ELEM_SIZE) + (i * 2)]);
1886 }
1887 }
1888 }
1889 else {
1890 memset(&data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE],
1891 0,
1892 sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE);
1893 }
1894
1895 MEM_freeN(masklay_shape->data);
1896 masklay_shape->data = data_resized;
1897 }
1898 else {
1899 CLOG_ERROR(&LOG,
1900 "vert mismatch %d != %d (frame %d)",
1901 masklay_shape->tot_vert,
1902 tot,
1903 masklay_shape->frame);
1904 }
1905 }
1906 }
1907}
1908
1910{
1911 /* the point has already been removed in this array so add one when comparing with the shapes */
1912 int tot = BKE_mask_layer_shape_totvert(masklay);
1913
1914 LISTBASE_FOREACH (MaskLayerShape *, masklay_shape, &masklay->splines_shapes) {
1915 if (tot == masklay_shape->tot_vert - count) {
1916 float *data_resized;
1917
1918 masklay_shape->tot_vert -= count;
1919 data_resized = MEM_calloc_arrayN<float>(
1920 masklay_shape->tot_vert * MASK_OBJECT_SHAPE_ELEM_SIZE, __func__);
1921 if (index > 0) {
1922 memcpy(data_resized,
1923 masklay_shape->data,
1924 index * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE);
1925 }
1926
1927 if (index != masklay_shape->tot_vert) {
1928 memcpy(&data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE],
1929 masklay_shape->data + ((index + count) * MASK_OBJECT_SHAPE_ELEM_SIZE),
1930 (masklay_shape->tot_vert - index) * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE);
1931 }
1932
1933 MEM_freeN(masklay_shape->data);
1934 masklay_shape->data = data_resized;
1935 }
1936 else {
1937 CLOG_ERROR(&LOG,
1938 "vert mismatch %d != %d (frame %d)",
1939 masklay_shape->tot_vert - count,
1940 tot,
1941 masklay_shape->frame);
1942 }
1943 }
1944}
1945
1947{
1948 return max_ii(1, mask->efra - mask->sfra);
1949}
1950
1951/*********************** clipboard *************************/
1952
1953static void mask_clipboard_free_ex(bool final_free)
1954{
1957 if (mask_clipboard.id_hash) {
1958 if (final_free) {
1959 BLI_ghash_free(mask_clipboard.id_hash, nullptr, MEM_freeN);
1960 }
1961 else {
1962 BLI_ghash_clear(mask_clipboard.id_hash, nullptr, MEM_freeN);
1963 }
1964 }
1965}
1966
1971
1973{
1974 /* Nothing to do if selection if disabled for the given layer. */
1975 if (mask_layer->visibility_flag & MASK_HIDE_SELECT) {
1976 return;
1977 }
1978
1980 if (mask_clipboard.id_hash == nullptr) {
1981 mask_clipboard.id_hash = BLI_ghash_ptr_new("mask clipboard ID hash");
1982 }
1983
1984 LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
1985 if (spline->flag & SELECT) {
1986 MaskSpline *spline_new = BKE_mask_spline_copy(spline);
1987 for (int i = 0; i < spline_new->tot_point; i++) {
1988 MaskSplinePoint *point = &spline_new->points[i];
1989 if (point->parent.id) {
1990 if (!BLI_ghash_lookup(mask_clipboard.id_hash, point->parent.id)) {
1991 int len = strlen(point->parent.id->name);
1992 char *name_copy = MEM_malloc_arrayN<char>(size_t(len) + 1, "mask clipboard ID name");
1993 memcpy(name_copy, point->parent.id->name, len + 1);
1994 BLI_ghash_insert(mask_clipboard.id_hash, point->parent.id, name_copy);
1995 }
1996 }
1997 }
1998
1999 BLI_addtail(&mask_clipboard.splines, spline_new);
2000 }
2001 }
2002}
2003
2005{
2006 return BLI_listbase_is_empty(&mask_clipboard.splines);
2007}
2008
2010{
2011 LISTBASE_FOREACH (MaskSpline *, spline, &mask_clipboard.splines) {
2012 MaskSpline *spline_new = BKE_mask_spline_copy(spline);
2013
2014 for (int i = 0; i < spline_new->tot_point; i++) {
2015 MaskSplinePoint *point = &spline_new->points[i];
2016 if (point->parent.id) {
2017 const char *id_name = static_cast<const char *>(
2018 BLI_ghash_lookup(mask_clipboard.id_hash, point->parent.id));
2019 ListBase *listbase;
2020
2021 BLI_assert(id_name != nullptr);
2022
2023 listbase = which_libbase(bmain, GS(id_name));
2024 point->parent.id = static_cast<ID *>(
2025 BLI_findstring(listbase, id_name + 2, offsetof(ID, name) + 2));
2026 }
2027 }
2028
2029 BLI_addtail(&mask_layer->splines, spline_new);
2030 }
2031}
void BKE_animdata_fix_paths_rename_all(struct ID *ref_id, const char *prefix, const char *oldName, const char *newName)
void BKE_nurb_handle_calc(BezTriple *bezt, BezTriple *prev, BezTriple *next, bool is_fcurve, char smoothing)
Definition curve.cc:3940
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:47
IDTypeInfo IDType_ID_MSK
void BKE_image_get_size_fl(Image *image, ImageUser *iuser, float r_size[2])
void BKE_image_get_aspect(Image *image, float *r_aspx, float *r_aspy)
void * BKE_libblock_alloc(Main *bmain, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1447
void id_fake_user_set(ID *id)
Definition lib_id.cc:396
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2631
@ IDWALK_CB_USER
#define BKE_LIB_FOREACHID_PROCESS_ID(data_, id_, cb_flag_)
ListBase * which_libbase(Main *bmain, short type)
Definition main.cc:902
eMaskhandleMode
Definition BKE_mask.h:36
@ MASK_HANDLE_MODE_INDIVIDUAL_HANDLES
Definition BKE_mask.h:38
@ MASK_HANDLE_MODE_STICK
Definition BKE_mask.h:37
void BKE_mask_layer_evaluate_deform(struct MaskLayer *masklay, float ctime)
eMaskWhichHandle
Definition BKE_mask.h:28
@ MASK_WHICH_HANDLE_BOTH
Definition BKE_mask.h:33
@ MASK_WHICH_HANDLE_RIGHT
Definition BKE_mask.h:32
@ MASK_WHICH_HANDLE_LEFT
Definition BKE_mask.h:31
@ MASK_WHICH_HANDLE_STICK
Definition BKE_mask.h:30
#define MASKPOINT_SEL_ALL(p)
Definition BKE_mask.h:301
eMaskSign
Definition BKE_mask.h:90
@ MASK_PROJ_ANY
Definition BKE_mask.h:92
@ MASK_PROJ_NEG
Definition BKE_mask.h:91
@ MASK_PROJ_POS
Definition BKE_mask.h:93
#define MASKPOINT_DESEL_ALL(p)
Definition BKE_mask.h:308
void BKE_mask_layer_evaluate_animation(struct MaskLayer *masklay, float ctime)
void BKE_movieclip_get_aspect(struct MovieClip *clip, float *aspx, float *aspy)
float BKE_movieclip_remap_scene_to_clip_frame(const struct MovieClip *clip, float framenr)
void BKE_movieclip_user_set_frame(struct MovieClipUser *user, int framenr)
void BKE_movieclip_get_size_fl(struct MovieClip *clip, const struct MovieClipUser *user, float r_size[2])
struct MovieTrackingPlaneTrack * BKE_tracking_object_find_plane_track_with_name(struct MovieTrackingObject *tracking_object, const char *name)
Definition tracking.cc:2005
struct MovieTrackingObject * BKE_tracking_object_get_named(struct MovieTracking *tracking, const char *name)
Definition tracking.cc:1966
void BKE_tracking_plane_marker_get_subframe_corners(struct MovieTrackingPlaneTrack *plane_track, float framenr, float corners[4][2])
Definition tracking.cc:1866
struct MovieTrackingTrack * BKE_tracking_object_find_track_with_name(struct MovieTrackingObject *tracking_object, const char *name)
Definition tracking.cc:1993
void BKE_tracking_marker_get_subframe_position(struct MovieTrackingTrack *track, float framenr, float pos[2])
Definition tracking.cc:1507
void BKE_tracking_homography_between_two_quads(float reference_corners[4][2], float corners[4][2], float H[3][3])
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define BLI_INLINE
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:855
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.cc:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void void BLI_listbase_sort(ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
bool BLI_remlink_safe(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:154
MINLINE int max_ii(int a, int b)
#define M_PI_2
#define M_PI
float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2])
void unit_m3(float m[3][3])
bool invert_m3_m3(float inverse[3][3], const float mat[3][3])
#define mul_m3_series(...)
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v2_v2v2fl(float r[2], const float a[2], const float b[2], float f)
float angle_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
void interp_v2_v2v2v2v2_cubic(float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2], float u)
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float len_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
void dist_ensure_v2_v2fl(float v1[2], const float v2[2], float dist)
MINLINE void copy_v3_v3(float r[3], const float a[3])
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 line_point_side_v2(const float l1[2], const float l2[2], const float pt[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v2(float r[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v2(float n[2])
void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2])
#define STRNCPY_UTF8(dst, src)
void BLI_uniquename(const struct ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_maxncpy) ATTR_NONNULL(1
#define ELEM(...)
#define LIKELY(x)
void BLO_write_float_array(BlendWriter *writer, int64_t num, const float *data_ptr)
void BLO_read_float_array(BlendDataReader *reader, int64_t array_size, float **ptr_p)
Definition readfile.cc:5809
#define BLO_write_id_struct(writer, struct_name, id_address, id)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define BLO_read_struct(reader, struct_name, ptr_p)
#define DATA_(msgid)
#define BLT_I18NCONTEXT_ID_MASK
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
void DEG_relations_tag_update(Main *bmain)
#define FILTER_ID_MC
Definition DNA_ID.h:1210
#define MAX_ID_NAME
Definition DNA_ID.h:373
#define FILTER_ID_MSK
Definition DNA_ID.h:1212
@ INDEX_ID_MSK
Definition DNA_ID.h:1306
@ ID_MC
@ ID_MSK
@ HD_VECT
@ HD_AUTO
@ HD_ALIGN_DOUBLESIDE
@ HD_ALIGN
#define DNA_struct_default_get(struct_name)
@ MASK_PARENT_POINT_TRACK
@ MASK_BLEND_MERGE_ADD
@ MASK_HIDE_SELECT
#define MASK_OBJECT_SHAPE_ELEM_SIZE
@ MASK_LAYERFLAG_FILL_OVERLAP
@ MASK_LAYERFLAG_FILL_DISCRETE
@ MASK_SPLINE_CYCLIC
@ MASK_SPLINE_INTERP_EASE
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
static void mask_blend_write(BlendWriter *writer, ID *id, const void *id_address)
void BKE_mask_clipboard_free()
void BKE_mask_layer_shape_unlink(MaskLayer *masklay, MaskLayerShape *masklay_shape)
void BKE_mask_coord_from_movieclip(MovieClip *clip, MovieClipUser *user, float r_co[2], const float co[2])
void BKE_mask_calc_handle_point(MaskSpline *spline, MaskSplinePoint *point)
void BKE_mask_layer_calc_handles(MaskLayer *masklay)
void BKE_mask_layer_shape_from_mask(MaskLayer *masklay, MaskLayerShape *masklay_shape)
float BKE_mask_point_weight(MaskSpline *spline, MaskSplinePoint *point, const float u)
MaskLayerShape * BKE_mask_layer_shape_verify_frame(MaskLayer *masklay, const int frame)
static void mask_layer_shape_to_mask_point(BezTriple *bezt, const float fp[MASK_OBJECT_SHAPE_ELEM_SIZE])
static int mask_layer_shape_sort_cb(const void *masklay_shape_a_ptr, const void *masklay_shape_b_ptr)
void BKE_mask_calc_handle_adjacent_interp(MaskSpline *spline, MaskSplinePoint *point, const float u)
static Mask * mask_alloc(Main *bmain, const char *name)
static void mask_runtime_reset(Mask *mask)
MaskSplinePoint * BKE_mask_spline_point_array_from_point(MaskSpline *spline, const MaskSplinePoint *point_ref)
static void mask_foreach_id(ID *id, LibraryForeachIDData *data)
void BKE_mask_get_handle_point_adjacent(MaskSpline *spline, MaskSplinePoint *point, MaskSplinePoint **r_point_prev, MaskSplinePoint **r_point_next)
void BKE_mask_layer_unique_name(Mask *mask, MaskLayer *masklay)
ListBase splines
void BKE_mask_point_add_uw(MaskSplinePoint *point, float u, float w)
void BKE_mask_clipboard_paste_to_layer(Main *bmain, MaskLayer *mask_layer)
static MaskSplinePoint * mask_spline_point_next(MaskSpline *spline, MaskSplinePoint *points_array, MaskSplinePoint *point)
BLI_INLINE void interp_v2_v2v2_flfl(float target[2], const float a[2], const float b[2], const float t, const float s)
MaskLayer * BKE_mask_layer_new(Mask *mask, const char *name)
Mask * BKE_mask_new(Main *bmain, const char *name)
void BKE_mask_point_normal(MaskSpline *spline, MaskSplinePoint *point, float u, float n[2])
void BKE_mask_layer_shape_changed_remove(MaskLayer *masklay, int index, int count)
void BKE_mask_layer_free_list(ListBase *masklayers)
MaskSpline * BKE_mask_spline_add(MaskLayer *masklay)
void BKE_mask_spline_direction_switch(MaskLayer *masklay, MaskSpline *spline)
bool BKE_mask_spline_remove(MaskLayer *mask_layer, MaskSpline *spline)
static void interp_weights_uv_v2_apply(const float uv[2], float r_pt[2], const float pt_a[2], const float pt_b[2])
void BKE_mask_point_select_set_handle(MaskSplinePoint *point, const eMaskWhichHandle which_handle, const bool do_select)
int BKE_mask_layer_shape_find_frame_range(MaskLayer *masklay, const float frame, MaskLayerShape **r_masklay_shape_a, MaskLayerShape **r_masklay_shape_b)
void BKE_mask_layer_shape_sort(MaskLayer *masklay)
MaskLayer * BKE_mask_layer_active(Mask *mask)
void BKE_mask_point_select_set(MaskSplinePoint *point, const bool do_select)
void BKE_mask_parent_init(MaskParent *parent)
eMaskhandleMode BKE_mask_point_handles_mode_get(const MaskSplinePoint *point)
void BKE_mask_point_handle(const MaskSplinePoint *point, eMaskWhichHandle which_handle, float r_handle[2])
static void mask_blend_read_data(BlendDataReader *reader, ID *id)
void BKE_mask_layer_copy_list(ListBase *masklayers_new, const ListBase *masklayers)
bool BKE_mask_clipboard_is_empty()
void BKE_mask_layer_shape_to_mask_interp(MaskLayer *masklay, MaskLayerShape *masklay_shape_a, MaskLayerShape *masklay_shape_b, const float fac)
void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float u, float co[2])
void BKE_mask_layer_rename(Mask *mask, MaskLayer *masklay, const char *oldname, const char *newname)
MaskSpline * BKE_mask_spline_copy(const MaskSpline *spline)
void BKE_mask_coord_to_image(Image *image, ImageUser *iuser, float r_co[2], const float co[2])
bool BKE_mask_layer_shape_spline_from_index(MaskLayer *masklay, int index, MaskSpline **r_masklay_shape, int *r_index)
static MaskSplinePoint * mask_spline_point_prev(MaskSpline *spline, MaskSplinePoint *points_array, MaskSplinePoint *point)
void BKE_mask_point_set_handle(MaskSplinePoint *point, eMaskWhichHandle which_handle, float loc[2], bool keep_direction, float orig_handle[2], float orig_vec[3][3])
void BKE_mask_point_parent_matrix_get(MaskSplinePoint *point, float ctime, float parent_matrix[3][3])
static void mask_layer_shape_from_mask_point(BezTriple *bezt, float fp[MASK_OBJECT_SHAPE_ELEM_SIZE])
float BKE_mask_point_weight_scalar(MaskSpline *spline, MaskSplinePoint *point, const float u)
void BKE_mask_coord_to_frame(float r_co[2], const float co[2], const float frame_size[2])
void BKE_mask_layer_free(MaskLayer *masklay)
void BKE_mask_coord_to_movieclip(MovieClip *clip, MovieClipUser *user, float r_co[2], const float co[2])
void BKE_mask_layer_shape_to_mask(MaskLayer *masklay, MaskLayerShape *masklay_shape)
MaskSplinePoint * BKE_mask_spline_point_array(MaskSpline *spline)
float BKE_mask_spline_project_co(MaskSpline *spline, MaskSplinePoint *point, float start_u, const float co[2], const eMaskSign sign)
static MaskSplinePoint * mask_spline_points_copy(const MaskSplinePoint *points, int tot_point)
static float mask_point_interp_weight(BezTriple *bezt, BezTriple *bezt_next, const float u)
static void mask_copy_data(Main *, std::optional< Library * >, ID *id_dst, const ID *id_src, const int)
void BKE_mask_coord_from_image(Image *image, ImageUser *iuser, float r_co[2], const float co[2])
void BKE_mask_layer_remove(Mask *mask, MaskLayer *masklay)
int BKE_mask_layer_shape_totvert(MaskLayer *masklay)
MaskLayerShape * BKE_mask_layer_shape_find_frame(MaskLayer *masklay, const int frame)
BezTriple * BKE_mask_spline_point_next_bezt(MaskSpline *spline, MaskSplinePoint *points_array, MaskSplinePoint *point)
static void mask_free_data(ID *id)
BLI_INLINE void orthogonal_direction_get(const float vec[2], float result[2])
void BKE_mask_layer_shape_free(MaskLayerShape *masklay_shape)
void BKE_mask_spline_ensure_deform(MaskSpline *spline)
void BKE_mask_spline_free(MaskSpline *spline)
void BKE_mask_layer_free_shapes(MaskLayer *masklay)
Free all animation keys for a mask layer.
int BKE_mask_layer_shape_spline_to_index(MaskLayer *masklay, MaskSpline *spline)
static void mask_calc_point_handle(MaskSplinePoint *point, MaskSplinePoint *point_prev, MaskSplinePoint *point_next)
int BKE_mask_get_duration(Mask *mask)
MaskLayerShape * BKE_mask_layer_shape_alloc(MaskLayer *masklay, const int frame)
static void mask_clipboard_free_ex(bool final_free)
void BKE_mask_point_free(MaskSplinePoint *point)
void BKE_mask_layer_evaluate(MaskLayer *masklay, const float ctime, const bool do_newframe)
void BKE_mask_layer_active_set(Mask *mask, MaskLayer *masklay)
void BKE_mask_point_direction_switch(MaskSplinePoint *point)
void BKE_mask_clipboard_copy_from_layer(MaskLayer *mask_layer)
void BKE_mask_spline_free_list(ListBase *splines)
GHash * id_hash
static void interp_weights_uv_v2_calc(float r_uv[2], const float pt[2], const float pt_a[2], const float pt_b[2])
MaskLayerShape * BKE_mask_layer_shape_duplicate(MaskLayerShape *masklay_shape)
void BKE_mask_coord_from_frame(float r_co[2], const float co[2], const float frame_size[2])
static struct @337113272175365276371025132263302043000243361112 mask_clipboard
MaskLayer * BKE_mask_layer_copy(const MaskLayer *masklay)
void BKE_mask_calc_tangent_polyline(MaskSpline *spline, MaskSplinePoint *point, float t[2])
void BKE_mask_layer_shape_changed_add(MaskLayer *masklay, int index, bool do_init, bool do_init_interpolate)
void BKE_mask_evaluate(Mask *mask, const float ctime, const bool do_newframe)
void BKE_mask_calc_handle_point_auto(MaskSpline *spline, MaskSplinePoint *point, const bool do_recalc_length)
Resets auto handles even for non-auto bezier points.
MaskSplinePointUW * BKE_mask_point_sort_uw(MaskSplinePoint *point, MaskSplinePointUW *uw)
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
nullptr float
#define SELECT
#define offsetof(t, d)
#define GS(x)
constexpr T sign(T) RET
#define abs
int count
#define LOG(level)
Definition log.h:97
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
size_t(* MEM_allocN_len)(const void *vmemh)
Definition mallocn.cc:36
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
#define N
#define H(x, y, z)
const char * name
float vec[3][3]
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
void * last
void * first
struct MaskLayerShape * prev
struct MaskLayerShape * next
struct MaskLayer * next
ListBase splines_shapes
char visibility_flag
ListBase splines
struct MaskSplinePoint * act_point
char name[64]
struct MaskSpline * act_spline
char parent[64]
float parent_orig[2]
float parent_corners_orig[4][2]
char sub_parent[64]
MaskSplinePointUW * uw
MaskParent parent
MaskParent parent
MaskSplinePoint * points_deform
struct MaskSpline * next
MaskSplinePoint * points
ListBase masklayers
struct MovieTracking tracking
i
Definition text_draw.cc:230
uint len
#define N_(msgid)