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