Blender  V3.3
transform_convert_action.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include "DNA_anim_types.h"
9 #include "DNA_gpencil_types.h"
10 #include "DNA_mask_types.h"
11 
12 #include "MEM_guardedalloc.h"
13 
14 #include "BLI_listbase.h"
15 #include "BLI_math.h"
16 #include "BLI_rect.h"
17 
18 #include "BKE_context.h"
19 #include "BKE_gpencil.h"
20 #include "BKE_key.h"
21 #include "BKE_mask.h"
22 #include "BKE_nla.h"
23 
24 #include "ED_anim_api.h"
25 #include "ED_keyframes_edit.h"
26 #include "ED_markers.h"
27 
28 #include "WM_api.h"
29 #include "WM_types.h"
30 
31 #include "transform.h"
32 #include "transform_snap.h"
33 
34 #include "transform_convert.h"
35 
36 /* helper struct for gp-frame transforms */
37 typedef struct tGPFtransdata {
38  union {
39  float val; /* where transdata writes transform */
40  float loc[3]; /* #td->val and #td->loc share the same pointer. */
41  };
42  int *sdata; /* pointer to gpf->framenum */
44 
45 /* -------------------------------------------------------------------- */
49 /* fully select selected beztriples, but only include if it's on the right side of cfra */
50 static int count_fcurve_keys(FCurve *fcu, char side, float cfra, bool is_prop_edit)
51 {
52  BezTriple *bezt;
53  int i, count = 0, count_all = 0;
54 
55  if (ELEM(NULL, fcu, fcu->bezt)) {
56  return count;
57  }
58 
59  /* only include points that occur on the right side of cfra */
60  for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
61  if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
62  /* no need to adjust the handle selection since they are assumed
63  * selected (like graph editor with SIPO_NOHANDLES) */
64  if (bezt->f2 & SELECT) {
65  count++;
66  }
67 
68  count_all++;
69  }
70  }
71 
72  if (is_prop_edit && count > 0) {
73  return count_all;
74  }
75  return count;
76 }
77 
78 /* fully select selected beztriples, but only include if it's on the right side of cfra */
79 static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra, bool is_prop_edit)
80 {
81  bGPDframe *gpf;
82  int count = 0, count_all = 0;
83 
84  if (gpl == NULL) {
85  return count;
86  }
87 
88  /* only include points that occur on the right side of cfra */
89  for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
90  if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
91  if (gpf->flag & GP_FRAME_SELECT) {
92  count++;
93  }
94  count_all++;
95  }
96  }
97 
98  if (is_prop_edit && count > 0) {
99  return count_all;
100  }
101  return count;
102 }
103 
104 /* fully select selected beztriples, but only include if it's on the right side of cfra */
105 static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra, bool is_prop_edit)
106 {
107  MaskLayerShape *masklayer_shape;
108  int count = 0, count_all = 0;
109 
110  if (masklay == NULL) {
111  return count;
112  }
113 
114  /* only include points that occur on the right side of cfra */
115  for (masklayer_shape = masklay->splines_shapes.first; masklayer_shape;
116  masklayer_shape = masklayer_shape->next) {
117  if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra)) {
118  if (masklayer_shape->flag & MASK_SHAPE_SELECT) {
119  count++;
120  }
121  count_all++;
122  }
123  }
124 
125  if (is_prop_edit && count > 0) {
126  return count_all;
127  }
128  return count;
129 }
130 
131 /* This function assigns the information to transdata */
132 static void TimeToTransData(
133  TransData *td, TransData2D *td2d, BezTriple *bezt, AnimData *adt, float ypos)
134 {
135  float *time = bezt->vec[1];
136 
137  /* Setup #TransData2D. */
138  td2d->loc[0] = *time;
139  td2d->loc2d = time;
140  td2d->h1 = bezt->vec[0];
141  td2d->h2 = bezt->vec[2];
142  copy_v2_v2(td2d->ih1, td2d->h1);
143  copy_v2_v2(td2d->ih2, td2d->h2);
144 
145  /* Setup #TransData. */
146 
147  /* Usually #td2d->loc is used here.
148  * But this is for when the original location is not float[3]. */
149  td->loc = time;
150 
151  copy_v3_v3(td->iloc, td->loc);
152  td->val = time;
153  td->ival = *(time);
154  td->center[0] = td->ival;
155  td->center[1] = ypos;
156 
157  /* Store the AnimData where this keyframe exists as a keyframe of the
158  * active action as #td->extra. */
159  td->extra = adt;
160 
161  if (bezt->f2 & SELECT) {
162  td->flag |= TD_SELECTED;
163  }
164 
165  /* Set flags to move handles as necessary. */
166  td->flag |= TD_MOVEHANDLE1 | TD_MOVEHANDLE2;
167 }
168 
169 /* This function advances the address to which td points to, so it must return
170  * the new address so that the next time new transform data is added, it doesn't
171  * overwrite the existing ones... i.e. td = IcuToTransData(td, icu, ob, side, cfra);
172  *
173  * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
174  * on the named side are used.
175  */
177  TransData2D **td2dv,
178  FCurve *fcu,
179  AnimData *adt,
180  char side,
181  float cfra,
182  bool is_prop_edit,
183  float ypos)
184 {
185  BezTriple *bezt;
186  TransData2D *td2d = *td2dv;
187  int i;
188 
189  if (ELEM(NULL, fcu, fcu->bezt)) {
190  return td;
191  }
192 
193  for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
194  /* only add selected keyframes (for now, proportional edit is not enabled) */
195  if (is_prop_edit || (bezt->f2 & SELECT)) { /* note this MUST match count_fcurve_keys(),
196  * so can't use BEZT_ISSEL_ANY() macro */
197  /* only add if on the right 'side' of the current frame */
198  if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
199  TimeToTransData(td, td2d, bezt, adt, ypos);
200 
201  td++;
202  td2d++;
203  }
204  }
205  }
206 
207  *td2dv = td2d;
208 
209  return td;
210 }
211 
221  tGPFtransdata *tfd,
222  bGPDlayer *gpl,
223  char side,
224  float cfra,
225  bool is_prop_edit,
226  float ypos)
227 {
228  bGPDframe *gpf;
229  int count = 0;
230 
231  /* check for select frames on right side of current frame */
232  for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
233  if (is_prop_edit || (gpf->flag & GP_FRAME_SELECT)) {
234  if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
235  tfd->val = (float)gpf->framenum;
236  tfd->sdata = &gpf->framenum;
237 
238  td->val = td->loc = &tfd->val;
239  td->ival = td->iloc[0] = tfd->val;
240 
241  td->center[0] = td->ival;
242  td->center[1] = ypos;
243 
244  /* Advance `td` now. */
245  td++;
246  tfd++;
247  count++;
248  }
249  }
250  }
251 
252  return count;
253 }
254 
255 /* refer to comment above #GPLayerToTransData, this is the same but for masks */
257  tGPFtransdata *tfd,
258  MaskLayer *masklay,
259  char side,
260  float cfra,
261  bool is_prop_edit,
262  float ypos)
263 {
264  MaskLayerShape *masklay_shape;
265  int count = 0;
266 
267  /* check for select frames on right side of current frame */
268  for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
269  masklay_shape = masklay_shape->next) {
270  if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
271  if (FrameOnMouseSide(side, (float)masklay_shape->frame, cfra)) {
272  tfd->val = (float)masklay_shape->frame;
273  tfd->sdata = &masklay_shape->frame;
274 
275  td->val = td->loc = &tfd->val;
276  td->ival = td->iloc[0] = tfd->val;
277 
278  td->center[0] = td->ival;
279  td->center[1] = ypos;
280 
281  /* advance td now */
282  td++;
283  tfd++;
284  count++;
285  }
286  }
287  }
288 
289  return count;
290 }
291 
293 {
294  Scene *scene = t->scene;
295  TransData *td = NULL;
296  TransData2D *td2d = NULL;
297  tGPFtransdata *tfd = NULL;
298 
299  rcti *mask = &t->region->v2d.mask;
300  rctf *datamask = &t->region->v2d.cur;
301 
302  float xsize = BLI_rctf_size_x(datamask);
303  float ysize = BLI_rctf_size_y(datamask);
304  float xmask = BLI_rcti_size_x(mask);
305  float ymask = BLI_rcti_size_y(mask);
306 
307  bAnimContext ac;
308  ListBase anim_data = {NULL, NULL};
309  bAnimListElem *ale;
310  int filter;
311  const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
312 
313  int count = 0;
314  int gpf_count = 0;
315  float cfra;
316  float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->region->v2d.cur);
317 
318  /* determine what type of data we are operating on */
319  if (ANIM_animdata_get_context(C, &ac) == 0) {
320  return;
321  }
322 
323  /* filter data */
325  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
326 
327  /* which side of the current frame should be allowed */
328  if (t->mode == TFM_TIME_EXTEND) {
329  t->frame_side = transform_convert_frame_side_dir_get(t, (float)scene->r.cfra);
330  }
331  else {
332  /* normal transform - both sides of current frame are considered */
333  t->frame_side = 'B';
334  }
335 
336  /* loop 1: fully select F-Curve keys and count how many BezTriples are selected */
337  for (ale = anim_data.first; ale; ale = ale->next) {
338  AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
339  int adt_count = 0;
340  /* convert current-frame to action-time (slightly less accurate, especially under
341  * higher scaling ratios, but is faster than converting all points)
342  */
343  if (adt) {
345  }
346  else {
347  cfra = (float)scene->r.cfra;
348  }
349 
351  adt_count = count_fcurve_keys(ale->key_data, t->frame_side, cfra, is_prop_edit);
352  }
353  else if (ale->type == ANIMTYPE_GPLAYER) {
354  adt_count = count_gplayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
355  }
356  else if (ale->type == ANIMTYPE_MASKLAYER) {
357  adt_count = count_masklayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
358  }
359  else {
360  BLI_assert(0);
361  }
362 
363  if (adt_count > 0) {
365  gpf_count += adt_count;
366  }
367  count += adt_count;
368  ale->tag = true;
369  }
370  }
371 
372  /* stop if trying to build list if nothing selected */
373  if (count == 0 && gpf_count == 0) {
374  /* cleanup temp list */
375  ANIM_animdata_freelist(&anim_data);
376  return;
377  }
378 
380 
381  /* allocate memory for data */
382  tc->data_len = count;
383 
384  tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(Action Editor)");
385  tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "transdata2d");
386  td = tc->data;
387  td2d = tc->data_2d;
388 
390  tc->data_gpf_len = gpf_count;
391  tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * gpf_count, "tGPFtransdata");
392  tc->custom.type.use_free = true;
393  }
394 
395  /* loop 2: build transdata array */
396  for (ale = anim_data.first; ale; ale = ale->next) {
397 
398  if (is_prop_edit && !ale->tag) {
399  continue;
400  }
401 
402  cfra = (float)scene->r.cfra;
403 
404  {
405  AnimData *adt;
406  adt = ANIM_nla_mapping_get(&ac, ale);
407  if (adt) {
409  }
410  }
411 
412  if (ale->type == ANIMTYPE_GPLAYER) {
413  bGPDlayer *gpl = (bGPDlayer *)ale->data;
414  int i;
415 
416  i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra, is_prop_edit, ypos);
417  td += i;
418  tfd += i;
419  }
420  else if (ale->type == ANIMTYPE_MASKLAYER) {
421  MaskLayer *masklay = (MaskLayer *)ale->data;
422  int i;
423 
424  i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra, is_prop_edit, ypos);
425  td += i;
426  tfd += i;
427  }
428  else {
429  AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
430  FCurve *fcu = (FCurve *)ale->key_data;
431 
432  td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra, is_prop_edit, ypos);
433  }
434  }
435 
436  /* calculate distances for proportional editing */
437  if (is_prop_edit) {
438  td = tc->data;
439 
440  for (ale = anim_data.first; ale; ale = ale->next) {
441  AnimData *adt;
442 
443  /* F-Curve may not have any keyframes */
444  if (!ale->tag) {
445  continue;
446  }
447 
448  adt = ANIM_nla_mapping_get(&ac, ale);
449  if (adt) {
451  }
452  else {
453  cfra = (float)scene->r.cfra;
454  }
455 
456  if (ale->type == ANIMTYPE_GPLAYER) {
457  bGPDlayer *gpl = (bGPDlayer *)ale->data;
458  bGPDframe *gpf;
459 
460  for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
461  if (gpf->flag & GP_FRAME_SELECT) {
462  td->dist = td->rdist = 0.0f;
463  }
464  else {
465  bGPDframe *gpf_iter;
466  int min = INT_MAX;
467  for (gpf_iter = gpl->frames.first; gpf_iter; gpf_iter = gpf_iter->next) {
468  if (gpf_iter->flag & GP_FRAME_SELECT) {
469  if (FrameOnMouseSide(t->frame_side, (float)gpf_iter->framenum, cfra)) {
470  int val = abs(gpf->framenum - gpf_iter->framenum);
471  if (val < min) {
472  min = val;
473  }
474  }
475  }
476  }
477  td->dist = td->rdist = min;
478  }
479  td++;
480  }
481  }
482  else if (ale->type == ANIMTYPE_MASKLAYER) {
483  MaskLayer *masklay = (MaskLayer *)ale->data;
484  MaskLayerShape *masklay_shape;
485 
486  for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
487  masklay_shape = masklay_shape->next) {
488  if (FrameOnMouseSide(t->frame_side, (float)masklay_shape->frame, cfra)) {
489  if (masklay_shape->flag & MASK_SHAPE_SELECT) {
490  td->dist = td->rdist = 0.0f;
491  }
492  else {
493  MaskLayerShape *masklay_iter;
494  int min = INT_MAX;
495  for (masklay_iter = masklay->splines_shapes.first; masklay_iter;
496  masklay_iter = masklay_iter->next) {
497  if (masklay_iter->flag & MASK_SHAPE_SELECT) {
498  if (FrameOnMouseSide(t->frame_side, (float)masklay_iter->frame, cfra)) {
499  int val = abs(masklay_shape->frame - masklay_iter->frame);
500  if (val < min) {
501  min = val;
502  }
503  }
504  }
505  }
506  td->dist = td->rdist = min;
507  }
508  td++;
509  }
510  }
511  }
512  else {
513  FCurve *fcu = (FCurve *)ale->key_data;
514  BezTriple *bezt;
515  int i;
516 
517  for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
518  if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
519  if (bezt->f2 & SELECT) {
520  td->dist = td->rdist = 0.0f;
521  }
522  else {
523  BezTriple *bezt_iter;
524  int j;
525  float min = FLT_MAX;
526  for (j = 0, bezt_iter = fcu->bezt; j < fcu->totvert; j++, bezt_iter++) {
527  if (bezt_iter->f2 & SELECT) {
528  if (FrameOnMouseSide(t->frame_side, (float)bezt_iter->vec[1][0], cfra)) {
529  float val = fabs(bezt->vec[1][0] - bezt_iter->vec[1][0]);
530  if (val < min) {
531  min = val;
532  }
533  }
534  }
535  }
536  td->dist = td->rdist = min;
537  }
538  td++;
539  }
540  }
541  }
542  }
543  }
544 
545  /* cleanup temp list */
546  ANIM_animdata_freelist(&anim_data);
547 }
548 
551 /* -------------------------------------------------------------------- */
555 /* This function helps flush transdata written to tempdata into the gp-frames. */
557 {
559  tGPFtransdata *tfd = tc->custom.type.data;
560 
561  /* flush data!
562  * Expects data_gpf_len to be set in the data container. */
563  for (int i = 0; i < tc->data_gpf_len; i++, tfd++) {
564  *(tfd->sdata) = round_fl_to_int(tfd->val);
565  }
566 }
567 
569 {
570  ViewLayer *view_layer = t->view_layer;
571  SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
572 
573  bAnimContext ac = {NULL};
574  ListBase anim_data = {NULL, NULL};
575  bAnimListElem *ale;
576  int filter;
577 
578  /* initialize relevant anim-context 'context' data from TransInfo data */
579  /* NOTE: sync this with the code in ANIM_animdata_get_context() */
580  ac.bmain = CTX_data_main(t->context);
581  ac.scene = t->scene;
582  ac.view_layer = t->view_layer;
583  ac.obact = OBACT(view_layer);
584  ac.area = t->area;
585  ac.region = t->region;
586  ac.sl = (t->area) ? t->area->spacedata.first : NULL;
587  ac.spacetype = (t->area) ? t->area->spacetype : 0;
588  ac.regiontype = (t->region) ? t->region->regiontype : 0;
589 
591 
592  /* perform flush */
594  /* flush transform values back to actual coordinates */
596  }
597 
598  /* Flush 2d vector. */
600  const short autosnap = getAnimEdit_SnapMode(t);
601  TransData *td;
602  TransData2D *td2d;
603  int i = 0;
604  for (td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
605  if ((autosnap != SACTSNAP_OFF) && (t->state != TRANS_CANCEL) && !(td->flag & TD_NOTIMESNAP)) {
606  transform_snap_anim_flush_data(t, td, autosnap, td->loc);
607  }
608 
609  /* Constrain Y. */
610  td->loc[1] = td->iloc[1];
611 
612  transform_convert_flush_handle2D(td, td2d, 0.0f);
613  }
614 
615  if (ac.datatype != ANIMCONT_MASK) {
616  /* Get animdata blocks visible in editor,
617  * assuming that these will be the ones where things changed. */
619  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
620 
621  /* just tag these animdata-blocks to recalc, assuming that some data there changed
622  * BUT only do this if realtime updates are enabled
623  */
624  if ((saction->flag & SACTION_NOREALTIMEUPDATES) == 0) {
625  for (ale = anim_data.first; ale; ale = ale->next) {
626  /* set refresh tags for objects using this animation */
627  ANIM_list_elem_update(CTX_data_main(t->context), t->scene, ale);
628  }
629  }
630 
631  /* now free temp channels */
632  ANIM_animdata_freelist(&anim_data);
633  }
634 }
635 
638 /* -------------------------------------------------------------------- */
642 static int masklay_shape_cmp_frame(void *thunk, const void *a, const void *b)
643 {
644  const MaskLayerShape *frame_a = a;
645  const MaskLayerShape *frame_b = b;
646 
647  if (frame_a->frame < frame_b->frame) {
648  return -1;
649  }
650  if (frame_a->frame > frame_b->frame) {
651  return 1;
652  }
653  *((bool *)thunk) = true;
654  /* selected last */
655  if ((frame_a->flag & MASK_SHAPE_SELECT) && ((frame_b->flag & MASK_SHAPE_SELECT) == 0)) {
656  return 1;
657  }
658  return 0;
659 }
660 
662 {
663  MaskLayer *masklay;
664 
665  for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
666  MaskLayerShape *masklay_shape, *masklay_shape_next;
667  bool is_double = false;
668 
670 
671  if (is_double) {
672  for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
673  masklay_shape = masklay_shape_next) {
674  masklay_shape_next = masklay_shape->next;
675  if (masklay_shape_next && masklay_shape->frame == masklay_shape_next->frame) {
676  BKE_mask_layer_shape_unlink(masklay, masklay_shape);
677  }
678  }
679  }
680 
681 #ifdef DEBUG
682  for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
683  masklay_shape = masklay_shape->next) {
684  BLI_assert(!masklay_shape->next || masklay_shape->frame < masklay_shape->next->frame);
685  }
686 #endif
687  }
688 
690 }
691 
692 /* Called by special_aftertrans_update to make sure selected gp-frames replace
693  * any other gp-frames which may reside on that frame (that are not selected).
694  * It also makes sure gp-frames are still stored in chronological order after
695  * transform.
696  */
697 static void posttrans_gpd_clean(bGPdata *gpd)
698 {
699  bGPDlayer *gpl;
700 
701  for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
702  bGPDframe *gpf, *gpfn;
703  bool is_double = false;
704 
705  BKE_gpencil_layer_frames_sort(gpl, &is_double);
706 
707  if (is_double) {
708  for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
709  gpfn = gpf->next;
710  if (gpfn && gpf->framenum == gpfn->framenum) {
712  }
713  }
714  }
715 
716 #ifdef DEBUG
717  for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
718  BLI_assert(!gpf->next || gpf->framenum < gpf->next->framenum);
719  }
720 #endif
721  }
722  /* set cache flag to dirty */
724 
726 }
727 
728 /* Called by special_aftertrans_update to make sure selected keyframes replace
729  * any other keyframes which may reside on that frame (that is not selected).
730  * remake_action_ipos should have already been called
731  */
733 {
734  ListBase anim_data = {NULL, NULL};
735  bAnimListElem *ale;
736  int filter;
737 
738  /* filter data */
740  ANIM_animdata_filter(ac, &anim_data, filter, act, ANIMCONT_ACTION);
741 
742  /* loop through relevant data, removing keyframes as appropriate
743  * - all keyframes are converted in/out of global time
744  */
745  for (ale = anim_data.first; ale; ale = ale->next) {
746  AnimData *adt = ANIM_nla_mapping_get(ac, ale);
747 
748  if (adt) {
749  ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
750  posttrans_fcurve_clean(ale->key_data, SELECT, false); /* only use handles in graph editor */
751  ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
752  }
753  else {
754  posttrans_fcurve_clean(ale->key_data, SELECT, false); /* only use handles in graph editor */
755  }
756  }
757 
758  /* free temp data */
759  ANIM_animdata_freelist(&anim_data);
760 }
761 
763 {
764  SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
765  bAnimContext ac;
766 
767  const bool canceled = (t->state == TRANS_CANCEL);
768  const bool duplicate = (t->mode == TFM_TIME_DUPLICATE);
769 
770  /* initialize relevant anim-context 'context' data */
771  if (ANIM_animdata_get_context(C, &ac) == 0) {
772  return;
773  }
774 
775  Object *ob = ac.obact;
776 
778  ListBase anim_data = {NULL, NULL};
779  bAnimListElem *ale;
781 
782  /* get channels to work on */
783  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
784 
785  for (ale = anim_data.first; ale; ale = ale->next) {
786  switch (ale->datatype) {
787  case ALE_GPFRAME:
788  ale->id->tag &= ~LIB_TAG_DOIT;
789  posttrans_gpd_clean((bGPdata *)ale->id);
790  break;
791 
792  case ALE_FCURVE: {
793  AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
794  FCurve *fcu = (FCurve *)ale->key_data;
795 
796  /* 3 cases here for curve cleanups:
797  * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
798  * 2) canceled == 0 -> user confirmed the transform,
799  * so duplicates should be removed
800  * 3) canceled + duplicate -> user canceled the transform,
801  * but we made duplicates, so get rid of these
802  */
803  if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
804  if (adt) {
805  ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
806  posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */
807  ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
808  }
809  else {
810  posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */
811  }
812  }
813  break;
814  }
815 
816  default:
817  BLI_assert_msg(false, "Keys cannot be transformed into this animation type.");
818  }
819  }
820 
821  /* free temp memory */
822  ANIM_animdata_freelist(&anim_data);
823  }
824  else if (ac.datatype == ANIMCONT_ACTION) { /* TODO: just integrate into the above. */
825  /* Depending on the lock status, draw necessary views */
826  /* FIXME: some of this stuff is not good. */
827  if (ob) {
828  if (ob->pose || BKE_key_from_object(ob)) {
830  }
831  else {
833  }
834  }
835 
836  /* 3 cases here for curve cleanups:
837  * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
838  * 2) canceled == 0 -> user confirmed the transform,
839  * so duplicates should be removed.
840  * 3) canceled + duplicate -> user canceled the transform,
841  * but we made duplicates, so get rid of these.
842  */
843  if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
844  posttrans_action_clean(&ac, (bAction *)ac.data);
845  }
846  }
847  else if (ac.datatype == ANIMCONT_GPENCIL) {
848  /* remove duplicate frames and also make sure points are in order! */
849  /* 3 cases here for curve cleanups:
850  * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
851  * 2) canceled == 0 -> user confirmed the transform,
852  * so duplicates should be removed
853  * 3) canceled + duplicate -> user canceled the transform,
854  * but we made duplicates, so get rid of these
855  */
856  if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
857  ListBase anim_data = {NULL, NULL};
858  const int filter = ANIMFILTER_DATA_VISIBLE;
859  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
860 
861  LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
862  if (ale->datatype == ALE_GPFRAME) {
863  ale->id->tag &= ~LIB_TAG_DOIT;
864  posttrans_gpd_clean((bGPdata *)ale->id);
865  }
866  }
867  ANIM_animdata_freelist(&anim_data);
868  }
869  }
870  else if (ac.datatype == ANIMCONT_MASK) {
871  /* remove duplicate frames and also make sure points are in order! */
872  /* 3 cases here for curve cleanups:
873  * 1) NOTRANSKEYCULL on:
874  * Cleanup of duplicates shouldn't be done.
875  * 2) canceled == 0:
876  * User confirmed the transform, so duplicates should be removed.
877  * 3) Canceled + duplicate:
878  * User canceled the transform, but we made duplicates, so get rid of these.
879  */
880  if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
881  ListBase anim_data = {NULL, NULL};
882  const int filter = ANIMFILTER_DATA_VISIBLE;
883  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
884 
885  LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
886  if (ale->datatype == ALE_MASKLAY) {
887  ale->id->tag &= ~LIB_TAG_DOIT;
888  posttrans_mask_clean((Mask *)ale->id);
889  }
890  }
891  ANIM_animdata_freelist(&anim_data);
892  }
893  }
894 
895  /* marker transform, not especially nice but we may want to move markers
896  * at the same time as keyframes in the dope sheet.
897  */
898  if ((saction->flag & SACTION_MARKERS_MOVE) && (canceled == 0)) {
899  if (t->mode == TFM_TIME_TRANSLATE) {
900 #if 0
901  if (ELEM(t->frame_side, 'L', 'R')) { /* TFM_TIME_EXTEND */
902  /* same as below */
904  ED_context_get_markers(C), t->scene, t->mode, t->values_final[0], t->frame_side);
905  }
906  else /* TFM_TIME_TRANSLATE */
907 #endif
908  {
910  ED_context_get_markers(C), t->scene, t->mode, t->values_final[0], t->frame_side);
911  }
912  }
913  else if (t->mode == TFM_TIME_SCALE) {
915  ED_context_get_markers(C), t->scene, t->mode, t->values_final[0], t->frame_side);
916  }
917  }
918 
919  /* make sure all F-Curves are set correctly */
920  if (!ELEM(ac.datatype, ANIMCONT_GPENCIL)) {
922  }
923 
924  /* clear flag that was set for time-slide drawing */
925  saction->flag &= ~SACTION_MOVING;
926 }
927 
931  /* flags */ (T_POINTS | T_2D_EDIT),
932  /* createTransData */ createTransActionData,
933  /* recalcData */ recalcData_actedit,
934  /* special_aftertrans_update */ special_aftertrans_update__actedit,
935 };
typedef float(TangentPoint)[2]
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
void BKE_gpencil_layer_frames_sort(struct bGPDlayer *gpl, bool *r_has_duplicate_frames)
Definition: gpencil.c:1553
bool BKE_gpencil_layer_frame_delete(struct bGPDlayer *gpl, struct bGPDframe *gpf)
Definition: gpencil.c:1396
struct Key * BKE_key_from_object(struct Object *ob)
Definition: key.c:1803
void BKE_mask_layer_shape_unlink(struct MaskLayer *masklay, struct MaskLayerShape *masklay_shape)
Definition: mask.c:1799
@ NLATIME_CONVERT_UNMAP
Definition: BKE_nla.h:357
float BKE_nla_tweakedit_remap(struct AnimData *adt, float cframe, short mode)
Definition: nla.c:642
#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)
Definition: BLI_listbase.h:336
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:190
BLI_INLINE float BLI_rctf_cent_y(const struct rctf *rct)
Definition: BLI_rect.h:181
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition: BLI_rect.h:186
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition: BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition: BLI_rect.h:198
#define ELEM(...)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:771
@ ID_RECALC_ANIMATION
Definition: DNA_ID.h:794
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ LIB_TAG_DOIT
Definition: DNA_ID.h:707
@ SACTSNAP_OFF
@ SACTION_NOTRANSKEYCULL
@ SACTION_MOVING
@ SACTION_MARKERS_MOVE
@ SACTION_NOREALTIMEUPDATES
@ GP_FRAME_SELECT
@ MASK_SHAPE_SELECT
#define OBACT(_view_layer)
@ ANIMTYPE_NLACURVE
Definition: ED_anim_api.h:202
@ ANIMTYPE_GPLAYER
Definition: ED_anim_api.h:233
@ ANIMTYPE_MASKLAYER
Definition: ED_anim_api.h:236
@ ANIMTYPE_FCURVE
Definition: ED_anim_api.h:199
@ ALE_GPFRAME
Definition: ED_anim_api.h:251
@ ALE_FCURVE
Definition: ED_anim_api.h:250
@ ALE_MASKLAY
Definition: ED_anim_api.h:252
@ ANIMCONT_MASK
Definition: ED_anim_api.h:112
@ ANIMCONT_SHAPEKEY
Definition: ED_anim_api.h:105
@ ANIMCONT_TIMELINE
Definition: ED_anim_api.h:113
@ ANIMCONT_DOPESHEET
Definition: ED_anim_api.h:107
@ ANIMCONT_ACTION
Definition: ED_anim_api.h:104
@ ANIMCONT_GPENCIL
Definition: ED_anim_api.h:106
@ ANIMFILTER_FOREDIT
Definition: ED_anim_api.h:312
@ ANIMFILTER_ANIMDATA
Definition: ED_anim_api.h:322
@ ANIMFILTER_DATA_VISIBLE
Definition: ED_anim_api.h:292
@ ANIMFILTER_FCURVESONLY
Definition: ED_anim_api.h:328
@ TFM_TIME_TRANSLATE
Definition: ED_transform.h:50
@ TFM_TIME_SCALE
Definition: ED_transform.h:52
@ TFM_TIME_DUPLICATE
Definition: ED_transform.h:54
@ TFM_TIME_EXTEND
Definition: ED_transform.h:53
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
#define NA_EDITED
Definition: WM_types.h:523
#define NC_GPENCIL
Definition: WM_types.h:349
#define NC_MASK
Definition: WM_types.h:348
void ANIM_animdata_freelist(ListBase *anim_data)
Definition: anim_deps.c:397
void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
Definition: anim_deps.c:44
AnimData * ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
Definition: anim_draw.c:216
void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, bool only_keys)
Definition: anim_draw.c:291
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
Definition: anim_filter.c:379
bool ANIM_animdata_context_getdata(bAnimContext *ac)
Definition: anim_filter.c:349
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_Flags filter_mode, void *data, eAnimCont_Types datatype)
Definition: anim_filter.c:3447
int ED_markers_post_apply_transform(ListBase *markers, Scene *scene, int mode, float value, char side)
Definition: anim_markers.c:103
ListBase * ED_context_get_markers(const bContext *C)
Definition: anim_markers.c:88
#define SELECT
double time
Scene scene
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.c:31
ccl_device_inline float2 fabs(const float2 &a)
Definition: math_float2.h:222
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
static unsigned a[3]
Definition: RandGen.cpp:78
T abs(const T &a)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
#define min(a, b)
Definition: sort.c:35
#define TRANS_DATA_CONTAINER_FIRST_SINGLE(t)
float vec[3][3]
uint8_t f2
BezTriple * bezt
int tag
Definition: DNA_ID.h:387
void * first
Definition: DNA_listBase.h:31
struct MaskLayerShape * next
struct MaskLayer * next
ListBase splines_shapes
struct bPose * pose
struct RenderData r
float * loc2d
float ih2[2]
float ih1[2]
float loc[3]
float * val
short datatype
Definition: ED_anim_api.h:62
void * data
Definition: ED_anim_api.h:60
struct bAnimListElem * next
Definition: ED_anim_api.h:127
void * key_data
Definition: ED_anim_api.h:146
struct ID * id
Definition: ED_anim_api.h:160
struct bGPDframe * next
struct bGPDlayer * next
ListBase frames
ListBase layers
void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const float y_fac)
bool FrameOnMouseSide(char side, float frame, float cframe)
void posttrans_fcurve_clean(FCurve *fcu, const int sel_flag, const bool use_handle)
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 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 int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, char side, float cfra, bool is_prop_edit, float ypos)
static int MaskLayerToTransData(TransData *td, tGPFtransdata *tfd, 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)
struct tGPFtransdata tGPFtransdata
static void createTransActionData(bContext *C, TransInfo *t)
static int count_fcurve_keys(FCurve *fcu, char side, float cfra, bool is_prop_edit)
static void posttrans_action_clean(bAnimContext *ac, bAction *act)
static void flushTransIntFrameActionData(TransInfo *t)
static void posttrans_gpd_clean(bGPdata *gpd)
static TransData * ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FCurve *fcu, AnimData *adt, char side, float cfra, bool is_prop_edit, float ypos)
@ TD_MOVEHANDLE1
@ TD_SELECTED
@ TD_NOTIMESNAP
@ TD_MOVEHANDLE2
short getAnimEdit_SnapMode(TransInfo *t)
void transform_snap_anim_flush_data(TransInfo *t, TransData *td, eAnimEdit_AutoSnap autosnap, float *r_val_final)
void WM_main_add_notifier(unsigned int type, void *reference)