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