Blender V5.0
transform_convert_action.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10
11#include "DNA_anim_types.h"
13#include "DNA_mask_types.h"
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_listbase.h"
18#include "BLI_math_vector.h"
19#include "BLI_rect.h"
20
21#include "BKE_context.hh"
22#include "BKE_fcurve.hh"
23#include "BKE_gpencil_legacy.h"
24#include "BKE_grease_pencil.hh"
25#include "BKE_key.hh"
26#include "BKE_layer.hh"
27#include "BKE_mask.h"
28#include "BKE_nla.hh"
29
30#include "ED_anim_api.hh"
31#include "ED_keyframes_edit.hh"
32#include "ED_markers.hh"
33
34#include "WM_api.hh"
35#include "WM_types.hh"
36
37#include "transform.hh"
38#include "transform_snap.hh"
39
40#include "transform_convert.hh"
41
42namespace blender::ed::transform {
43
44/* Weak way of identifying whether TransData was set by #GPLayerToTransData or
45 * #MaskLayerToTransData. This way we can identify whether the #td->loc2d_i is a pointer to an
46 * integer value and we can correctly flush in #recalcData_actedit. */
47static bool is_td2d_int(TransData2D *td2d)
48{
49 return td2d->loc2d_i && td2d->h1 == nullptr;
50}
51
52/* -------------------------------------------------------------------- */
55
56/* Add a fake user to ensure drawings are not deleted during transform when a frame is overwritten
57 * temporarily. The drawing_index of any existing frame will also remain valid. */
59{
60 using namespace bke::greasepencil;
61
62 for (const GreasePencilDrawingBase *drawing_base : grease_pencil.drawings()) {
63 /* Only actual drawings have a user count, ignore drawing references. */
64 if (drawing_base->type != GP_DRAWING) {
65 continue;
66 }
67
68 const Drawing &drawing = reinterpret_cast<const GreasePencilDrawing *>(drawing_base)->wrap();
69 drawing.runtime->fake_user = true;
70 }
71}
72
73/* Remove fake users from drawings after frame data has been restored. After this drawing data can
74 * be freed and drawing indices may become invalid. */
76{
77 using namespace bke::greasepencil;
78
79 for (const GreasePencilDrawingBase *drawing_base : grease_pencil.drawings()) {
80 /* Only actual drawings have a user count, ignore drawing references. */
81 if (drawing_base->type != GP_DRAWING) {
82 continue;
83 }
84
85 const Drawing &drawing = reinterpret_cast<const GreasePencilDrawing *>(drawing_base)->wrap();
86 drawing.runtime->fake_user = false;
87 }
88}
89
92 const Span<int> frames_affected,
93 const bool use_duplicates)
94{
95 using namespace bke::greasepencil;
96 LayerTransformData &trans_data = layer.runtime->trans_data_;
97
98 if (trans_data.status != LayerTransformData::TRANS_CLEAR) {
99 return false;
100 }
101
102 /* "Freeze" drawing indices by adding a fake user to each drawing. This ensures the drawing_index
103 * in frame data remains valid and no data is lost if the drawing is temporarily unused during
104 * transform. */
106
107 /* Initialize the transformation data structure, by storing in separate maps frames that will
108 * remain static during the transformation, and frames that are affected by the
109 * transformation.
110 */
111 trans_data.frames_static = layer.frames();
112 trans_data.frames_transformed.clear();
113
114 for (const int frame_number : frames_affected) {
115 const bool was_duplicated = use_duplicates &&
116 trans_data.duplicated_frames_buffer.contains(frame_number);
117
118 /* Get the frame that is going to be affected by the transformation :
119 * if the frame was duplicated, then its the duplicated frame which is being transformed,
120 * otherwise it is the original frame, stored in the layer. */
121 const Map<int, GreasePencilFrame> &frame_map = was_duplicated ?
122 trans_data.duplicated_frames_buffer :
123 layer.frames();
124
125 const GreasePencilFrame frame_transformed = frame_map.lookup(frame_number);
126 trans_data.frames_transformed.add_overwrite(frame_number, frame_transformed);
127
128 if (!was_duplicated) {
129 /* Remove from the static map each frame that is affected by the transformation and that was
130 * not duplicated. Note that if the frame was duplicated, then the original frame is not
131 * affected by the transformation. */
132 trans_data.frames_static.remove_as(frame_number);
133 }
134 }
135
136 trans_data.frames_duration.clear();
137 trans_data.frames_destination.clear();
138
139 for (const auto [frame_number, frame] : layer.frames().items()) {
140 if (frame.is_end()) {
141 continue;
142 }
143
144 /* Store frames' duration to keep them visually correct while moving the frames. */
145 trans_data.frames_duration.add(frame_number, layer.get_frame_duration_at(frame_number));
146 }
147
148 trans_data.status = LayerTransformData::TRANS_INIT;
149 return true;
150}
151
153{
154 using namespace bke::greasepencil;
155 LayerTransformData &trans_data = layer.runtime->trans_data_;
156
157 /* If the layer frame map was affected by the transformation, set its status to initialized so
158 * that the frames map gets reset the next time this modal function is called.
159 */
160 if (trans_data.status == LayerTransformData::TRANS_CLEAR) {
161 return false;
162 }
163 trans_data.status = LayerTransformData::TRANS_INIT;
164 return true;
165}
166
168 const int src_frame_number,
169 const int dst_frame_number)
170{
171 using namespace bke::greasepencil;
172 LayerTransformData &trans_data = layer.runtime->trans_data_;
173
174 if (trans_data.status == LayerTransformData::TRANS_CLEAR) {
175 return false;
176 }
177
178 if (trans_data.status == LayerTransformData::TRANS_INIT) {
179 /* The transdata was only initialized. No transformation was applied yet.
180 * The frame mapping is always defined relatively to the initial frame map, so we first need
181 * to initialize the frames in its static state, meaning containing only the frames not
182 * affected by the transformation. */
183 layer.frames_for_write() = trans_data.frames_static;
185 trans_data.status = LayerTransformData::TRANS_RUNNING;
186 }
187
188 if (!trans_data.frames_transformed.contains(src_frame_number)) {
189 /* If the frame is not affected by the transformation, then do nothing. */
190 return false;
191 }
192
193 /* Apply the transformation directly in the layer frame map, so that we display the transformed
194 * frame numbers. We don't want to edit the frames or remove any drawing here. This will be
195 * done at once at the end of the transformation. */
196 const GreasePencilFrame src_frame = trans_data.frames_transformed.lookup(src_frame_number);
197 const int src_duration = trans_data.frames_duration.lookup_default(src_frame_number, 0);
198
199 layer.remove_frame(dst_frame_number);
200
201 GreasePencilFrame *frame = layer.add_frame(dst_frame_number, src_duration);
202 *frame = src_frame;
203
204 trans_data.frames_destination.add_overwrite(src_frame_number, dst_frame_number);
205
206 return true;
207}
208
211 const bool canceled,
212 const bool duplicate)
213{
214 using namespace bke::greasepencil;
215 LayerTransformData &trans_data = layer.runtime->trans_data_;
216
217 if (trans_data.status == LayerTransformData::TRANS_CLEAR) {
218 /* The layer was not affected by the transformation, so do nothing. */
219 return false;
220 }
221
222 /* Reset the frames to their initial state. */
223 layer.frames_for_write() = trans_data.frames_static;
224 for (const auto [frame_number, frame] : trans_data.frames_transformed.items()) {
225 if (trans_data.duplicated_frames_buffer.contains(frame_number)) {
226 continue;
227 }
228 layer.frames_for_write().add_overwrite(frame_number, frame);
229 }
231
232 if (!canceled) {
233 /* Moves all the selected frames according to the transformation, and inserts the potential
234 * duplicate frames in the layer. */
235 grease_pencil.move_duplicate_frames(
236 layer, trans_data.frames_destination, trans_data.duplicated_frames_buffer);
237 }
238
239 if (canceled && duplicate) {
240 /* Duplicates were done, so we need to delete the corresponding duplicate drawings. */
241 for (const GreasePencilFrame &duplicate_frame : trans_data.duplicated_frames_buffer.values()) {
242 GreasePencilDrawingBase *drawing_base = grease_pencil.drawing(duplicate_frame.drawing_index);
243 if (drawing_base->type == GP_DRAWING) {
244 reinterpret_cast<GreasePencilDrawing *>(drawing_base)->wrap().remove_user();
245 }
246 }
247 }
248
249 /* All frame data is updated, safe to remove the fake user and remove unused drawings. */
251 grease_pencil.remove_drawings_with_no_users();
252
253 /* Clear the frames copy. */
254 trans_data.frames_static.clear();
255 trans_data.frames_transformed.clear();
256 trans_data.frames_destination.clear();
257 trans_data.duplicated_frames_buffer.clear();
258 trans_data.status = LayerTransformData::TRANS_CLEAR;
259
260 return true;
261}
262
264
265/* -------------------------------------------------------------------- */
268
272static int count_fcurve_keys(FCurve *fcu, char side, float cfra, bool is_prop_edit)
273{
274 BezTriple *bezt;
275 int i, count = 0, count_all = 0;
276
277 if (ELEM(nullptr, fcu, fcu->bezt)) {
278 return count;
279 }
280
281 /* Only include points that occur on the right side of cfra. */
282 for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
283 if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
284 /* No need to adjust the handle selection since they are assumed
285 * selected (like graph editor with #SIPO_NOHANDLES). */
286 if (bezt->f2 & SELECT) {
287 count++;
288 }
289
290 count_all++;
291 }
292 }
293
294 if (is_prop_edit && count > 0) {
295 return count_all;
296 }
297 return count;
298}
299
303static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra, bool is_prop_edit)
304{
305 int count = 0, count_all = 0;
306
307 if (gpl == nullptr) {
308 return count;
309 }
310
311 /* Only include points that occur on the right side of cfra. */
312 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
313 if (FrameOnMouseSide(side, float(gpf->framenum), cfra)) {
314 if (gpf->flag & GP_FRAME_SELECT) {
315 count++;
316 }
317 count_all++;
318 }
319 }
320
321 if (is_prop_edit && count > 0) {
322 return count_all;
323 }
324 return count;
325}
326
328 const char side,
329 const float cfra,
330 const bool is_prop_edit,
331 const bool use_duplicated)
332{
333 if (layer == nullptr) {
334 return 0;
335 }
336
337 int count_selected = 0;
338 int count_all = 0;
339
340 if (use_duplicated) {
341 /* Only count the frames that were duplicated. */
342 count_selected += layer->runtime->trans_data_.duplicated_frames_buffer.size();
343 count_all += count_selected;
344 }
345 else {
346 /* Only include points that occur on the right side of cfra. */
347 for (const auto &[frame_number, frame] : layer->frames().items()) {
348 if (!FrameOnMouseSide(side, float(frame_number), cfra)) {
349 continue;
350 }
351 if (frame.is_selected()) {
352 count_selected++;
353 }
354 count_all++;
355 }
356 }
357
358 if (is_prop_edit && count_selected > 0) {
359 return count_all;
360 }
361 return count_selected;
362}
363
365static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra, bool is_prop_edit)
366{
367 int count = 0, count_all = 0;
368
369 if (masklay == nullptr) {
370 return count;
371 }
372
373 /* Only include points that occur on the right side of cfra. */
374 LISTBASE_FOREACH (MaskLayerShape *, masklayer_shape, &masklay->splines_shapes) {
375 if (FrameOnMouseSide(side, float(masklayer_shape->frame), cfra)) {
376 if (masklayer_shape->flag & MASK_SHAPE_SELECT) {
377 count++;
378 }
379 count_all++;
380 }
381 }
382
383 if (is_prop_edit && count > 0) {
384 return count_all;
385 }
386 return count;
387}
388
389/* This function assigns the information to transdata. */
390static void TimeToTransData(
391 TransData *td, TransData2D *td2d, BezTriple *bezt, bAnimListElem *ale, float ypos)
392{
393 float *time = bezt->vec[1];
394
395 /* Setup #TransData2D. */
396 td2d->loc[0] = *time;
397 td2d->loc2d = time;
398 td2d->h1 = bezt->vec[0];
399 td2d->h2 = bezt->vec[2];
400 copy_v2_v2(td2d->ih1, td2d->h1);
401 copy_v2_v2(td2d->ih2, td2d->h2);
402
403 /* Setup #TransData. */
404
405 /* Usually #td2d->loc is used here.
406 * But this is for when the original location is not float[3]. */
407 td->loc = time;
408
409 copy_v3_v3(td->iloc, td->loc);
410 td->val = time;
411 td->ival = *(time);
413 td->center[1] = ypos;
414
415 /* Store the AnimData where this keyframe exists as a keyframe of the
416 * active action as #td->extra.
417 *
418 * We do this conditionally as a hacky way of indicating whether NLA remapping
419 * should be done. This is left over from old code, most of which was changed
420 * in #130440 to avoid using `adt == nullptr` as an indicator for that. This
421 * was left that way because updating it cleanly was more involved than made
422 * sense for the bug fix in #130440. */
423 if (ANIM_nla_mapping_allowed(ale)) {
424 td->extra = ale->adt;
425 }
426
427 if (bezt->f2 & SELECT) {
428 td->flag |= TD_SELECTED;
429 }
430
431 /* Set flags to move handles as necessary. */
433
434 BLI_assert(!is_td2d_int(td2d));
435}
436
437/* This function advances the address to which td points to, so it must return
438 * the new address so that the next time new transform data is added, it doesn't
439 * overwrite the existing ones... i.e. td = IcuToTransData(td, icu, ob, side, cfra);
440 *
441 * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
442 * on the named side are used.
443 */
445 TransData2D **td2dv,
446 FCurve *fcu,
447 bAnimListElem *ale,
448 char side,
449 float cfra,
450 bool is_prop_edit,
451 float ypos)
452{
453 BezTriple *bezt;
454 TransData2D *td2d = *td2dv;
455 int i;
456
457 if (ELEM(nullptr, fcu, fcu->bezt)) {
458 return td;
459 }
460
461 for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
462 /* Only add selected keyframes (for now, proportional edit is not enabled). */
463 if (is_prop_edit || (bezt->f2 & SELECT))
464 { /* Note this MUST match #count_fcurve_keys(), so can't use #BEZT_ISSEL_ANY() macro. */
465 /* Only add if on the right 'side' of the current frame. */
466 if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
467 TimeToTransData(td, td2d, bezt, ale, ypos);
468
469 td++;
470 td2d++;
471 }
472 }
473 }
474
475 *td2dv = td2d;
476
477 return td;
478}
479
489 TransData2D *td2d,
490 bGPDlayer *gpl,
491 char side,
492 float cfra,
493 bool is_prop_edit,
494 float ypos)
495{
496 int count = 0;
497
498 /* Check for select frames on right side of current frame. */
499 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
500 const bool is_selected = (gpf->flag & GP_FRAME_SELECT) != 0;
501 if (is_prop_edit || is_selected) {
502 if (FrameOnMouseSide(side, float(gpf->framenum), cfra)) {
503 td2d->loc[0] = float(gpf->framenum);
504 td2d->loc2d_i = &gpf->framenum;
505
506 td->loc = td->val = td2d->loc;
507 td->iloc[0] = td->ival = td2d->loc[0];
508
509 td->center[0] = td->ival;
510 td->center[1] = ypos;
511
512 if (is_selected) {
513 td->flag = TD_SELECTED;
514 }
515
516 BLI_assert(is_td2d_int(td2d));
517
518 /* Advance `td` now. */
519 td++;
520 td2d++;
521 count++;
522 }
523 }
524 }
525
526 return count;
527}
528
535 TransData2D *td2d,
536 GreasePencil *grease_pencil,
538 const char side,
539 const float cfra,
540 const bool is_prop_edit,
541 const float ypos,
542 const bool duplicate)
543{
544 using namespace bke::greasepencil;
545
546 int total_trans_frames = 0;
547 bool any_frame_affected = false;
548 Vector<int> frames_affected;
549
550 const auto grease_pencil_frame_to_trans_data = [&](const int frame_number,
551 const bool frame_selected) {
552 /* We only add transform data for selected frames that are on the right side of current frame.
553 * If proportional edit is set, then we should also account for non selected frames.
554 */
555 if ((!is_prop_edit && !frame_selected) || !FrameOnMouseSide(side, frame_number, cfra)) {
556 return;
557 }
558
559 td2d->loc[0] = float(frame_number);
560
561 td->val = td->loc = &td2d->loc[0];
562 td->ival = td->iloc[0] = td2d->loc[0];
563
564 td->center[0] = td->ival;
565 td->center[1] = ypos;
566
567 if (frame_selected) {
568 td->flag |= TD_SELECTED;
569 }
570 /* Set a pointer to the layer in the transform data so that we can apply the transformation
571 * while the operator is running.
572 */
574 td->extra = layer;
575
576 BLI_assert(!is_td2d_int(td2d));
577
578 /* Advance `td` now. */
579 td++;
580 td2d++;
581 total_trans_frames++;
582
583 frames_affected.append(frame_number);
584 any_frame_affected = true;
585 };
586
587 const Map<int, GreasePencilFrame> &frame_map =
588 duplicate ? (layer->runtime->trans_data_.duplicated_frames_buffer) : layer->frames();
589
590 for (const auto [frame_number, frame] : frame_map.items()) {
591 grease_pencil_frame_to_trans_data(frame_number, frame.is_selected());
592 }
593
594 if (total_trans_frames == 0) {
595 return total_trans_frames;
596 }
597
598 /* If it was not previously done, initialize the transform data in the layer, and if some frames
599 * are actually concerned by the transform. */
600 if (any_frame_affected) {
602 *grease_pencil, *layer, frames_affected.as_span(), duplicate);
603 }
604
605 return total_trans_frames;
606}
607
612 TransData2D *td2d,
613 MaskLayer *masklay,
614 char side,
615 float cfra,
616 bool is_prop_edit,
617 float ypos)
618{
619 int count = 0;
620
621 /* Check for select frames on right side of current frame. */
622 LISTBASE_FOREACH (MaskLayerShape *, masklay_shape, &masklay->splines_shapes) {
623 if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
624 if (FrameOnMouseSide(side, float(masklay_shape->frame), cfra)) {
625 td2d->loc[0] = float(masklay_shape->frame);
626 td2d->loc2d_i = &masklay_shape->frame;
627
628 td->loc = td->val = td2d->loc;
629 td->iloc[0] = td->ival = td2d->loc[0];
630
631 td->center[0] = td->ival;
632 td->center[1] = ypos;
633
634 BLI_assert(is_td2d_int(td2d));
635
636 /* Advance td now. */
637 td++;
638 td2d++;
639 count++;
640 }
641 }
642 }
643
644 return count;
645}
646
648{
649 Scene *scene = t->scene;
650 TransData *td = nullptr;
651 TransData2D *td2d = nullptr;
652
653 /* The T_DUPLICATED_KEYFRAMES flag is only set if we made some duplicates of the selected frames,
654 * and they are the ones that are being transformed. */
655 const bool use_duplicated = (t->flag & T_DUPLICATED_KEYFRAMES) != 0;
656
657 const rcti *mask = &t->region->v2d.mask;
658 const rctf *datamask = &t->region->v2d.cur;
659
660 float xsize = BLI_rctf_size_x(datamask);
661 float ysize = BLI_rctf_size_y(datamask);
662 float xmask = BLI_rcti_size_x(mask);
663 float ymask = BLI_rcti_size_y(mask);
664
665 bAnimContext ac;
666 ListBase anim_data = {nullptr, nullptr};
667 int filter;
668 const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
669
670 int count = 0;
671 int gpf_count = 0;
672 float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->region->v2d.cur);
673
674 /* Determine what type of data we are operating on. */
675 if (ANIM_animdata_get_context(C, &ac) == 0) {
676 return;
677 }
678
679 /* Filter data. */
682 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
683
684 /* Which side of the current frame should be allowed. */
685 if (t->mode == TFM_TIME_EXTEND) {
687 }
688 else {
689 /* Normal transform - both sides of current frame are considered. */
690 t->frame_side = 'B';
691 }
692
693 /* Loop 1: fully select F-Curve keys and count how many BezTriples are selected. */
694 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
695 int ale_count = 0;
696 /* Convert current-frame to action-time (slightly less accurate, especially under
697 * higher scaling ratios, but is faster than converting all points). */
698 const float cfra = ANIM_nla_tweakedit_remap(ale, float(scene->r.cfra), NLATIME_CONVERT_UNMAP);
699
700 switch (ale->type) {
701 case ANIMTYPE_FCURVE:
703 ale_count = count_fcurve_keys(
704 static_cast<FCurve *>(ale->key_data), t->frame_side, cfra, is_prop_edit);
705 break;
706 case ANIMTYPE_GPLAYER:
707 ale_count = count_gplayer_frames(
708 static_cast<bGPDlayer *>(ale->data), t->frame_side, cfra, is_prop_edit);
709 break;
711 using namespace bke::greasepencil;
712 ale_count = count_grease_pencil_frames(
713 static_cast<Layer *>(ale->data), t->frame_side, cfra, is_prop_edit, use_duplicated);
714 break;
715 }
717 ale_count = count_masklayer_frames(
718 static_cast<MaskLayer *>(ale->data), t->frame_side, cfra, is_prop_edit);
719 break;
720 case ANIMTYPE_NONE:
723 case ANIMTYPE_SUMMARY:
724 case ANIMTYPE_SCENE:
725 case ANIMTYPE_OBJECT:
726 case ANIMTYPE_GROUP:
732 case ANIMTYPE_DSMAT:
733 case ANIMTYPE_DSLAM:
734 case ANIMTYPE_DSCAM:
736 case ANIMTYPE_DSCUR:
737 case ANIMTYPE_DSSKEY:
738 case ANIMTYPE_DSWOR:
739 case ANIMTYPE_DSNTREE:
740 case ANIMTYPE_DSPART:
741 case ANIMTYPE_DSMBALL:
742 case ANIMTYPE_DSARM:
743 case ANIMTYPE_DSMESH:
744 case ANIMTYPE_DSTEX:
745 case ANIMTYPE_DSLAT:
747 case ANIMTYPE_DSSPK:
749 case ANIMTYPE_DSMCLIP:
750 case ANIMTYPE_DSHAIR:
760 case ANIMTYPE_PALETTE:
763 break;
764 }
765
766 if (ale_count > 0) {
767 if (ELEM(ale->type, ANIMTYPE_GPLAYER, ANIMTYPE_MASKLAYER)) {
768 gpf_count += ale_count;
769 }
770 count += ale_count;
771 ale->tag = true;
772 }
773 }
774
775 /* Stop if trying to build list if nothing selected. */
776 if (count == 0 && gpf_count == 0) {
777 /* Cleanup temp list. */
778 ANIM_animdata_freelist(&anim_data);
779 return;
780 }
781
783
784 /* Allocate memory for data. */
785 tc->data_len = count;
786
787 tc->data = MEM_calloc_arrayN<TransData>(tc->data_len, "TransData(Action Editor)");
788 tc->data_2d = MEM_calloc_arrayN<TransData2D>(tc->data_len, "transdata2d");
789 td = tc->data;
790 td2d = tc->data_2d;
791
792 /* Loop 2: build transdata array. */
793 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
794
795 if (is_prop_edit && !ale->tag) {
796 continue;
797 }
798
799 const float cfra = ANIM_nla_tweakedit_remap(ale, float(scene->r.cfra), NLATIME_CONVERT_UNMAP);
800
801 if (ale->type == ANIMTYPE_GPLAYER) {
802 bGPDlayer *gpl = (bGPDlayer *)ale->data;
803 int i;
804
805 i = GPLayerToTransData(td, td2d, gpl, t->frame_side, cfra, is_prop_edit, ypos);
806 td += i;
807 td2d += i;
808 }
809 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
810 using namespace bke::greasepencil;
811 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
812 Layer *layer = static_cast<Layer *>(ale->data);
813 int i;
814
816 td, td2d, grease_pencil, layer, t->frame_side, cfra, is_prop_edit, ypos, use_duplicated);
817 td += i;
818 td2d += i;
819 }
820 else if (ale->type == ANIMTYPE_MASKLAYER) {
821 MaskLayer *masklay = (MaskLayer *)ale->data;
822 int i;
823
824 i = MaskLayerToTransData(td, td2d, masklay, t->frame_side, cfra, is_prop_edit, ypos);
825 td += i;
826 td2d += i;
827 }
828 else {
829 FCurve *fcu = (FCurve *)ale->key_data;
830 td = ActionFCurveToTransData(td, &td2d, fcu, ale, t->frame_side, cfra, is_prop_edit, ypos);
831 }
832 }
833
834 /* Calculate distances for proportional editing. */
835 if (is_prop_edit) {
836 td = tc->data;
837
838 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
839 /* F-Curve may not have any keyframes. */
840 if (!ale->tag) {
841 continue;
842 }
843
844 const float cfra = ANIM_nla_tweakedit_remap(
845 ale, float(scene->r.cfra), NLATIME_CONVERT_UNMAP);
846
847 if (ale->type == ANIMTYPE_GPLAYER) {
848 bGPDlayer *gpl = (bGPDlayer *)ale->data;
849
850 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
851 if (gpf->flag & GP_FRAME_SELECT) {
852 td->dist = td->rdist = 0.0f;
853 }
854 else {
855 int min = INT_MAX;
856 LISTBASE_FOREACH (bGPDframe *, gpf_iter, &gpl->frames) {
857 if (gpf_iter->flag & GP_FRAME_SELECT) {
858 if (FrameOnMouseSide(t->frame_side, float(gpf_iter->framenum), cfra)) {
859 int val = abs(gpf->framenum - gpf_iter->framenum);
860 min = std::min(val, min);
861 }
862 }
863 }
864 td->dist = td->rdist = min;
865 }
866 td++;
867 }
868 }
869 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
870 using namespace bke::greasepencil;
871 Layer *layer = static_cast<Layer *>(ale->data);
872
873 const auto grease_pencil_closest_selected_frame = [&](const int frame_number,
874 const bool frame_selected) {
875 if (frame_selected) {
876 td->dist = td->rdist = 0.0f;
877 ++td;
878 return;
879 }
880
881 int closest_selected = INT_MAX;
882 for (const auto [neighbor_frame_number, neighbor_frame] : layer->frames().items()) {
883 if (!neighbor_frame.is_selected() ||
884 !FrameOnMouseSide(t->frame_side, float(neighbor_frame_number), cfra))
885 {
886 continue;
887 }
888 const int distance = abs(neighbor_frame_number - frame_number);
889 closest_selected = std::min(closest_selected, distance);
890 }
891
892 td->dist = td->rdist = closest_selected;
893 ++td;
894 };
895
896 for (const auto [frame_number, frame] : layer->frames().items()) {
897 grease_pencil_closest_selected_frame(frame_number, frame.is_selected());
898 }
899
900 if (use_duplicated) {
901 /* Also count for duplicated frames. */
902 for (const auto [frame_number, frame] :
903 layer->runtime->trans_data_.duplicated_frames_buffer.items())
904 {
905 grease_pencil_closest_selected_frame(frame_number, frame.is_selected());
906 }
907 }
908 }
909 else if (ale->type == ANIMTYPE_MASKLAYER) {
910 MaskLayer *masklay = (MaskLayer *)ale->data;
911
912 LISTBASE_FOREACH (MaskLayerShape *, masklay_shape, &masklay->splines_shapes) {
913 if (FrameOnMouseSide(t->frame_side, float(masklay_shape->frame), cfra)) {
914 if (masklay_shape->flag & MASK_SHAPE_SELECT) {
915 td->dist = td->rdist = 0.0f;
916 }
917 else {
918 int min = INT_MAX;
919 LISTBASE_FOREACH (MaskLayerShape *, masklay_iter, &masklay->splines_shapes) {
920 if (masklay_iter->flag & MASK_SHAPE_SELECT) {
921 if (FrameOnMouseSide(t->frame_side, float(masklay_iter->frame), cfra)) {
922 int val = abs(masklay_shape->frame - masklay_iter->frame);
923 min = std::min(val, min);
924 }
925 }
926 }
927 td->dist = td->rdist = min;
928 }
929 td++;
930 }
931 }
932 }
933 else {
934 FCurve *fcu = (FCurve *)ale->key_data;
935 BezTriple *bezt;
936 int i;
937
938 for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
939 if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
940 if (bezt->f2 & SELECT) {
941 td->dist = td->rdist = 0.0f;
942 }
943 else {
944 BezTriple *bezt_iter;
945 int j;
946 float min = FLT_MAX;
947 for (j = 0, bezt_iter = fcu->bezt; j < fcu->totvert; j++, bezt_iter++) {
948 if (bezt_iter->f2 & SELECT) {
949 if (FrameOnMouseSide(t->frame_side, bezt_iter->vec[1][0], cfra)) {
950 float val = fabs(bezt->vec[1][0] - bezt_iter->vec[1][0]);
951 min = std::min(val, min);
952 }
953 }
954 }
955 td->dist = td->rdist = min;
956 }
957 td++;
958 }
959 }
960 }
961 }
962 }
963
964 /* Cleanup temp list. */
965 ANIM_animdata_freelist(&anim_data);
966}
967
969
970/* -------------------------------------------------------------------- */
973
974static void invert_snap(eSnapMode &snap_mode)
975{
976 /* Make snapping work like before 4.0 where pressing CTRL will switch between snapping to seconds
977 * and frames. */
978 if (snap_mode & SCE_SNAP_TO_FRAME) {
979 snap_mode &= ~SCE_SNAP_TO_FRAME;
980 snap_mode |= SCE_SNAP_TO_SECOND;
981 }
982 else if (snap_mode & SCE_SNAP_TO_SECOND) {
983 snap_mode &= ~SCE_SNAP_TO_SECOND;
984 snap_mode |= SCE_SNAP_TO_FRAME;
985 }
986}
987
989{
990 ViewLayer *view_layer = t->view_layer;
991 SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
992
993 bAnimContext ac = {nullptr};
994 ListBase anim_data = {nullptr, nullptr};
995 int filter;
996
998
999 /* Initialize relevant anim-context `context` data from #TransInfo data. */
1000 /* NOTE: sync this with the code in #ANIM_animdata_get_context(). */
1001 ac.bmain = CTX_data_main(t->context);
1002 ac.scene = t->scene;
1003 ac.view_layer = t->view_layer;
1004 ac.obact = BKE_view_layer_active_object_get(view_layer);
1005 ac.area = t->area;
1006 ac.region = t->region;
1007 ac.sl = static_cast<SpaceLink *>((t->area) ? t->area->spacedata.first : nullptr);
1008 ac.spacetype = eSpace_Type((t->area) ? t->area->spacetype : 0);
1009 ac.regiontype = eRegion_Type((t->region) ? t->region->regiontype : 0);
1010
1012
1013 /* Flush 2d vector. */
1015 eSnapMode snap_mode = t->tsnap.mode;
1016 if (t->modifiers & MOD_SNAP_INVERT) {
1017 invert_snap(snap_mode);
1018 }
1019
1020 TransData *td;
1021 TransData2D *td2d;
1022 int i = 0;
1023 for (td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
1024 if ((t->tsnap.flag & SCE_SNAP) && (t->state != TRANS_CANCEL) && !(td->flag & TD_NOTIMESNAP)) {
1025 transform_snap_anim_flush_data(t, td, snap_mode, td->loc);
1026 }
1027
1028 /* Constrain Y. */
1029 td->loc[1] = td->iloc[1];
1030
1031 transform_convert_flush_handle2D(td, td2d, 0.0f);
1032
1033 if ((td->flag & TD_GREASE_PENCIL_FRAME) != 0) {
1035 round_fl_to_int(td->ival),
1036 round_fl_to_int(td2d->loc[0]));
1037 }
1038 else if (is_td2d_int(td2d)) {
1039 /* (Grease Pencil Legacy)
1040 * This helps flush transdata written to tempdata into the gp-frames. */
1041 *td2d->loc2d_i = round_fl_to_int(td2d->loc[0]);
1042 }
1043 }
1044
1045 if (ac.datatype != ANIMCONT_MASK) {
1046 /* Get animdata blocks visible in editor,
1047 * assuming that these will be the ones where things changed. */
1050 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
1051
1052 /* Just tag these animdata-blocks to recalc, assuming that some data there changed
1053 * BUT only do this if realtime updates are enabled. */
1054 if ((saction->flag & SACTION_NOREALTIMEUPDATES) == 0) {
1055 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1056 /* Set refresh tags for objects using this animation. */
1058 }
1059
1060 /* Now free temp channels. */
1061 ANIM_animdata_freelist(&anim_data);
1062 }
1063
1064 {
1067 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
1068
1069 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1070 if (ale->type != ANIMTYPE_GREASE_PENCIL_LAYER) {
1071 continue;
1072 }
1074 ANIM_id_update(ale->bmain, ale->id);
1075 }
1076 ANIM_animdata_freelist(&anim_data);
1077 }
1078 }
1079}
1080
1082
1083/* -------------------------------------------------------------------- */
1086
1087static int masklay_shape_cmp_frame(void *thunk, const void *a, const void *b)
1088{
1089 const MaskLayerShape *frame_a = static_cast<const MaskLayerShape *>(a);
1090 const MaskLayerShape *frame_b = static_cast<const MaskLayerShape *>(b);
1091
1092 if (frame_a->frame < frame_b->frame) {
1093 return -1;
1094 }
1095 if (frame_a->frame > frame_b->frame) {
1096 return 1;
1097 }
1098 *((bool *)thunk) = true;
1099 /* Selected last. */
1100 if ((frame_a->flag & MASK_SHAPE_SELECT) && ((frame_b->flag & MASK_SHAPE_SELECT) == 0)) {
1101 return 1;
1102 }
1103 return 0;
1104}
1105
1107{
1108 LISTBASE_FOREACH (MaskLayer *, masklay, &mask->masklayers) {
1109 MaskLayerShape *masklay_shape, *masklay_shape_next;
1110 bool is_double = false;
1111
1112 BLI_listbase_sort_r(&masklay->splines_shapes, masklay_shape_cmp_frame, &is_double);
1113
1114 if (is_double) {
1115 for (masklay_shape = static_cast<MaskLayerShape *>(masklay->splines_shapes.first);
1116 masklay_shape;
1117 masklay_shape = masklay_shape_next)
1118 {
1119 masklay_shape_next = masklay_shape->next;
1120 if (masklay_shape_next && masklay_shape->frame == masklay_shape_next->frame) {
1121 BKE_mask_layer_shape_unlink(masklay, masklay_shape);
1122 }
1123 }
1124 }
1125
1126#ifndef NDEBUG
1127 for (masklay_shape = static_cast<MaskLayerShape *>(masklay->splines_shapes.first);
1128 masklay_shape;
1129 masklay_shape = masklay_shape->next)
1130 {
1131 BLI_assert(!masklay_shape->next || masklay_shape->frame < masklay_shape->next->frame);
1132 }
1133#endif
1134 }
1135
1137}
1138
1139/* Called by special_aftertrans_update to make sure selected gp-frames replace
1140 * any other gp-frames which may reside on that frame (that are not selected).
1141 * It also makes sure gp-frames are still stored in chronological order after
1142 * transform.
1143 */
1145{
1146 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1147 bGPDframe *gpf, *gpfn;
1148 bool is_double = false;
1149
1150 BKE_gpencil_layer_frames_sort(gpl, &is_double);
1151
1152 if (is_double) {
1153 for (gpf = static_cast<bGPDframe *>(gpl->frames.first); gpf; gpf = gpfn) {
1154 gpfn = gpf->next;
1155 if (gpfn && gpf->framenum == gpfn->framenum) {
1157 }
1158 }
1159 }
1160
1161#ifndef NDEBUG
1162 for (gpf = static_cast<bGPDframe *>(gpl->frames.first); gpf; gpf = gpf->next) {
1163 BLI_assert(!gpf->next || gpf->framenum < gpf->next->framenum);
1164 }
1165#endif
1166 }
1167 /* Set cache flag to dirty. */
1169
1171}
1172
1179{
1180 ListBase anim_data = {nullptr, nullptr};
1181 int filter;
1182
1183 /* Filter data. */
1186
1187 /* Loop through relevant data, removing keyframes as appropriate.
1188 * - all keyframes are converted in/out of global time.
1189 */
1190 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1192 ale, static_cast<FCurve *>(ale->key_data), false, false);
1193 BKE_fcurve_merge_duplicate_keys(static_cast<FCurve *>(ale->key_data),
1194 SELECT,
1195 false); /* Only use handles in graph editor. */
1197 ale, static_cast<FCurve *>(ale->key_data), true, false);
1198 }
1199
1200 /* Free temp data. */
1201 ANIM_animdata_freelist(&anim_data);
1202}
1203
1205{
1206 SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
1207 bAnimContext ac;
1208
1209 const bool canceled = (t->state == TRANS_CANCEL);
1210 const bool duplicate = (t->flag & T_DUPLICATED_KEYFRAMES) != 0;
1211
1212 /* Initialize relevant anim-context 'context' data. */
1213 if (ANIM_animdata_get_context(C, &ac) == 0) {
1214 return;
1215 }
1216
1217 Object *ob = ac.obact;
1218
1220 ListBase anim_data = {nullptr, nullptr};
1222
1223 /* Get channels to work on. */
1225 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
1226
1227 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1228 switch (ale->datatype) {
1229 case ALE_GPFRAME:
1230 ale->id->tag &= ~ID_TAG_DOIT;
1231 posttrans_gpd_clean((bGPdata *)ale->id);
1232 break;
1233
1234 case ALE_FCURVE: {
1235 FCurve *fcu = (FCurve *)ale->key_data;
1236
1237 /* 3 cases here for curve cleanups:
1238 * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done.
1239 * 2) canceled == 0 -> user confirmed the transform,
1240 * so duplicates should be removed.
1241 * 3) canceled + duplicate -> user canceled the transform,
1242 * but we made duplicates, so get rid of these.
1243 */
1244 if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
1245 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcu, false, false);
1247 fcu, SELECT, false); /* Only use handles in graph editor. */
1248 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcu, true, false);
1249 }
1250 break;
1251 }
1252 case ALE_GREASE_PENCIL_CEL: {
1253 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
1255 *static_cast<bke::greasepencil::Layer *>(ale->data),
1256 canceled,
1257 duplicate);
1258 break;
1259 }
1260 default:
1261 BLI_assert_msg(false, "Keys cannot be transformed into this animation type.");
1262 }
1263 }
1264
1265 /* Free temp memory. */
1266 ANIM_animdata_freelist(&anim_data);
1267 }
1268 else if (ac.datatype == ANIMCONT_ACTION) { /* TODO: just integrate into the above. */
1269 /* Depending on the lock status, draw necessary views. */
1270 /* FIXME: some of this stuff is not good. */
1271 if (ob) {
1272 if (ob->pose || BKE_key_from_object(ob)) {
1274 }
1275 else {
1277 }
1278 }
1279
1280 /* 3 cases here for curve cleanups:
1281 * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
1282 * 2) canceled == 0 -> user confirmed the transform,
1283 * so duplicates should be removed.
1284 * 3) canceled + duplicate -> user canceled the transform,
1285 * but we made duplicates, so get rid of these.
1286 */
1287 if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
1289 }
1290 }
1291 else if (ac.datatype == ANIMCONT_GPENCIL) {
1292 /* Remove duplicate frames and also make sure points are in order! */
1293 /* 3 cases here for curve cleanups:
1294 * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done.
1295 * 2) canceled == 0 -> user confirmed the transform,
1296 * so duplicates should be removed.
1297 * 3) canceled + duplicate -> user canceled the transform,
1298 * but we made duplicates, so get rid of these.
1299 */
1300 ListBase anim_data = {nullptr, nullptr};
1301 const int filter = ANIMFILTER_DATA_VISIBLE;
1303 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
1304
1305 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1306 switch (ale->datatype) {
1307 case ALE_GPFRAME:
1308 /* Grease Pencil legacy. */
1309 if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
1310 ale->id->tag &= ~ID_TAG_DOIT;
1311 posttrans_gpd_clean((bGPdata *)ale->id);
1312 }
1313 break;
1314
1315 case ALE_GREASE_PENCIL_CEL: {
1316 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
1318 *static_cast<bke::greasepencil::Layer *>(ale->data),
1319 canceled,
1320 duplicate);
1321 break;
1322 }
1323
1324 default:
1325 break;
1326 }
1327 }
1328 ANIM_animdata_freelist(&anim_data);
1329 }
1330 else if (ac.datatype == ANIMCONT_MASK) {
1331 /* Remove duplicate frames and also make sure points are in order! */
1332 /* 3 cases here for curve cleanups:
1333 * 1) NOTRANSKEYCULL on:
1334 * Cleanup of duplicates shouldn't be done.
1335 * 2) canceled == 0:
1336 * User confirmed the transform, so duplicates should be removed.
1337 * 3) Canceled + duplicate:
1338 * User canceled the transform, but we made duplicates, so get rid of these.
1339 */
1340 if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
1341 ListBase anim_data = {nullptr, nullptr};
1342 const int filter = ANIMFILTER_DATA_VISIBLE;
1344 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
1345
1346 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1347 if (ale->datatype == ALE_MASKLAY) {
1348 ale->id->tag &= ~ID_TAG_DOIT;
1349 posttrans_mask_clean((Mask *)ale->id);
1350 }
1351 }
1352 ANIM_animdata_freelist(&anim_data);
1353 }
1354 }
1355
1356 /* Marker transform, not especially nice but we may want to move markers
1357 * at the same time as keyframes in the dope sheet. */
1358 if ((saction->flag & SACTION_MARKERS_MOVE) && (canceled == 0)) {
1359 if (t->mode == TFM_TIME_TRANSLATE) {
1360#if 0
1361 if (ELEM(t->frame_side, 'L', 'R')) { /* #TFM_TIME_EXTEND. */
1362 /* Same as below. */
1365 }
1366 else /* #TFM_TIME_TRANSLATE. */
1367#endif
1368 {
1371 }
1372 }
1373 else if (t->mode == TFM_TIME_SCALE) {
1376 }
1377 }
1378
1379 /* Make sure all F-Curves are set correctly. */
1380 if (!ELEM(ac.datatype, ANIMCONT_GPENCIL)) {
1382 }
1383
1384 /* Clear flag that was set for time-slide drawing. */
1385 saction->flag &= ~SACTION_MOVING;
1386}
1387
1389
1391 /*flags*/ (T_POINTS | T_2D_EDIT),
1392 /*create_trans_data*/ createTransActionData,
1393 /*recalc_data*/ recalcData_actedit,
1394 /*special_aftertrans_update*/ special_aftertrans_update__actedit,
1395};
1396
1397} // namespace blender::ed::transform
Main * CTX_data_main(const bContext *C)
void BKE_fcurve_merge_duplicate_keys(FCurve *fcu, const int sel_flag, const bool use_handle)
void BKE_gpencil_layer_frames_sort(struct bGPDlayer *gpl, bool *r_has_duplicate_frames)
bool BKE_gpencil_layer_frame_delete(struct bGPDlayer *gpl, struct bGPDframe *gpf)
Low-level operations for grease pencil.
Key * BKE_key_from_object(Object *ob)
Definition key.cc:1791
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
void BKE_mask_layer_shape_unlink(struct MaskLayer *masklay, struct MaskLayerShape *masklay_shape)
@ NLATIME_CONVERT_MAP
Definition BKE_nla.hh:552
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:549
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
void void void BLI_listbase_sort_r(ListBase *listbase, int(*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1
MINLINE int round_fl_to_int(float a)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE float BLI_rctf_cent_y(const struct rctf *rct)
Definition BLI_rect.h:189
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_TAG_DOIT
Definition DNA_ID.h:1036
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1054
@ ID_RECALC_ANIMATION
Definition DNA_ID.h:1077
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
@ SACTION_NOTRANSKEYCULL
@ SACTION_MOVING
@ SACTION_MARKERS_MOVE
@ SACTION_NOREALTIMEUPDATES
@ MASK_SHAPE_SELECT
@ SCE_SNAP
@ SCE_SNAP_TO_FRAME
@ SCE_SNAP_TO_SECOND
eRegion_Type
eSpace_Type
@ ANIMTYPE_DSSPK
@ ANIMTYPE_DSTEX
@ ANIMTYPE_SUMMARY
@ ANIMTYPE_DSNTREE
@ ANIMTYPE_NLACURVE
@ ANIMTYPE_SHAPEKEY
@ ANIMTYPE_DSMBALL
@ ANIMTYPE_DSCAM
@ ANIMTYPE_DSLIGHTPROBE
@ ANIMTYPE_DSPOINTCLOUD
@ ANIMTYPE_FILLDRIVERS
@ ANIMTYPE_NONE
@ ANIMTYPE_DSPART
@ ANIMTYPE_DSLINESTYLE
@ ANIMTYPE_GROUP
@ ANIMTYPE_ACTION_SLOT
@ ANIMTYPE_SPECIALDATA__UNUSED
@ ANIMTYPE_GREASE_PENCIL_DATABLOCK
@ ANIMTYPE_DSCUR
@ ANIMTYPE_SCENE
@ ANIMTYPE_DSARM
@ ANIMTYPE_NLACONTROLS
@ ANIMTYPE_GPLAYER
@ ANIMTYPE_MASKDATABLOCK
@ ANIMTYPE_ANIMDATA
@ ANIMTYPE_MASKLAYER
@ ANIMTYPE_DSGPENCIL
@ ANIMTYPE_DSLAT
@ ANIMTYPE_NLAACTION
@ ANIMTYPE_DSMCLIP
@ ANIMTYPE_DSMAT
@ ANIMTYPE_NUM_TYPES
@ ANIMTYPE_DSCACHEFILE
@ ANIMTYPE_DSVOLUME
@ ANIMTYPE_FCURVE
@ ANIMTYPE_DSLAM
@ ANIMTYPE_PALETTE
@ ANIMTYPE_GREASE_PENCIL_LAYER
@ ANIMTYPE_FILLACT_LAYERED
@ ANIMTYPE_FILLACTD
@ ANIMTYPE_OBJECT
@ ANIMTYPE_DSMESH
@ ANIMTYPE_GREASE_PENCIL_LAYER_GROUP
@ ANIMTYPE_NLATRACK
@ ANIMTYPE_DSWOR
@ ANIMTYPE_DSSKEY
@ ANIMTYPE_DSHAIR
@ ALE_GREASE_PENCIL_CEL
@ ALE_GPFRAME
@ ALE_FCURVE
@ ALE_MASKLAY
eAnimCont_Types
@ ANIMCONT_MASK
@ ANIMCONT_SHAPEKEY
@ ANIMCONT_TIMELINE
@ ANIMCONT_DOPESHEET
@ ANIMCONT_ACTION
@ ANIMCONT_GPENCIL
eAnimFilter_Flags
@ ANIMFILTER_FOREDIT
@ ANIMFILTER_ANIMDATA
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_FCURVESONLY
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
#define NA_EDITED
Definition WM_types.hh:584
#define NC_GPENCIL
Definition WM_types.hh:399
#define NC_MASK
Definition WM_types.hh:398
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:463
void ANIM_id_update(Main *bmain, ID *id)
Definition anim_deps.cc:103
void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
Definition anim_deps.cc:52
void ANIM_nla_mapping_apply_if_needed_fcurve(bAnimListElem *ale, FCurve *fcu, const bool restore, const bool only_keys)
Definition anim_draw.cc:401
bool ANIM_nla_mapping_allowed(const bAnimListElem *ale)
Definition anim_draw.cc:274
float ANIM_nla_tweakedit_remap(bAnimListElem *ale, const float cframe, const eNlaTime_ConvertModes mode)
Definition anim_draw.cc:324
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
bool ANIM_animdata_context_getdata(bAnimContext *ac)
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, const eAnimFilter_Flags filter_mode, void *data, const eAnimCont_Types datatype)
int ED_markers_post_apply_transform(ListBase *markers, Scene *scene, int mode, float value, char side)
ListBase * ED_context_get_markers(const bContext *C)
void clear()
Definition BLI_map.hh:1038
bool add_overwrite(const Key &key, const Value &value)
Definition BLI_map.hh:325
ItemIterator items() const &
Definition BLI_map.hh:902
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
ItemIterator items() const &
Definition BLI_map.hh:902
void append(const T &value)
Span< T > as_span() const
bool remove_frame(FramesMapKeyT key)
const Map< FramesMapKeyT, GreasePencilFrame > & frames() const
GreasePencilFrame * add_frame(FramesMapKeyT key, int duration=0)
int get_frame_duration_at(const int frame_number) const
Map< FramesMapKeyT, GreasePencilFrame > & frames_for_write()
nullptr float
#define SELECT
#define filter
#define abs
float distance(VecOp< float, D >, VecOp< float, D >) RET
int count
void ANIM_editkeyframes_refresh(bAnimContext *ac)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
ccl_device_inline float2 fabs(const float2 a)
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static bool grease_pencil_layer_reset_trans_data(bke::greasepencil::Layer &layer)
static TransData * ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FCurve *fcu, bAnimListElem *ale, char side, float cfra, bool is_prop_edit, float ypos)
static void invert_snap(eSnapMode &snap_mode)
static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra, bool is_prop_edit)
static bool is_td2d_int(TransData2D *td2d)
static void grease_pencil_transdata_add_fake_drawing_users(const GreasePencil &grease_pencil)
static void posttrans_action_clean(bAnimContext *ac, bAction *act)
static void posttrans_gpd_clean(bGPdata *gpd)
static void grease_pencil_transdata_remove_fake_drawing_users(const GreasePencil &grease_pencil)
static void TimeToTransData(TransData *td, TransData2D *td2d, BezTriple *bezt, bAnimListElem *ale, float ypos)
char transform_convert_frame_side_dir_get(TransInfo *t, float cframe)
static int count_grease_pencil_frames(const bke::greasepencil::Layer *layer, const char side, const float cfra, const bool is_prop_edit, const bool use_duplicated)
static bool grease_pencil_layer_initialize_trans_data(const GreasePencil &grease_pencil, bke::greasepencil::Layer &layer, const Span< int > frames_affected, const bool use_duplicates)
static bool grease_pencil_layer_update_trans_data(bke::greasepencil::Layer &layer, const int src_frame_number, const int dst_frame_number)
static int count_fcurve_keys(FCurve *fcu, char side, float cfra, bool is_prop_edit)
static void createTransActionData(bContext *C, TransInfo *t)
static bool grease_pencil_layer_apply_trans_data(GreasePencil &grease_pencil, bke::greasepencil::Layer &layer, const bool canceled, const bool duplicate)
static void posttrans_mask_clean(Mask *mask)
TransConvertTypeInfo TransConvertType_Action
bool FrameOnMouseSide(char side, float frame, float cframe)
static int GPLayerToTransData(TransData *td, TransData2D *td2d, bGPDlayer *gpl, char side, float cfra, bool is_prop_edit, float ypos)
void transform_snap_anim_flush_data(TransInfo *t, TransData *td, eSnapMode snap_mode, float *r_val_final)
static void special_aftertrans_update__actedit(bContext *C, TransInfo *t)
static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra, bool is_prop_edit)
static int masklay_shape_cmp_frame(void *thunk, const void *a, const void *b)
void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const float y_fac)
static void recalcData_actedit(TransInfo *t)
static int MaskLayerToTransData(TransData *td, TransData2D *td2d, MaskLayer *masklay, char side, float cfra, bool is_prop_edit, float ypos)
static int GreasePencilLayerToTransData(TransData *td, TransData2D *td2d, GreasePencil *grease_pencil, bke::greasepencil::Layer *layer, const char side, const float cfra, const bool is_prop_edit, const float ypos, const bool duplicate)
float wrap(float value, float max, float min)
Definition node_math.h:103
#define FLT_MAX
Definition stdcycles.h:14
float vec[3][3]
BezTriple * bezt
GreasePencilDrawingRuntimeHandle * runtime
GreasePencilLayerRuntimeHandle * runtime
void * first
struct MaskLayerShape * next
ListBase splines_shapes
struct bPose * pose
struct RenderData r
ListBase spacedata
SpaceLink * sl
eAnimCont_Types datatype
eSpace_Type spacetype
ViewLayer * view_layer
ARegion * region
Object * obact
eRegion_Type regiontype
ScrArea * area
AnimData * adt
struct bGPDframe * next
i
Definition text_draw.cc:230
#define TRANS_DATA_CONTAINER_FIRST_SINGLE(t)
Definition transform.hh:39
conversion and adaptation of different datablocks to a common struct.
void WM_main_add_notifier(uint type, void *reference)