Blender  V2.93
keyframes_general.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) 2008 Blender Foundation
17  * All rights reserved.
18  */
19 
24 #include <float.h>
25 #include <math.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "MEM_guardedalloc.h"
30 
31 #include "BLI_blenlib.h"
32 #include "BLI_math.h"
33 #include "BLI_string_utils.h"
34 #include "BLI_utildefines.h"
35 
36 #include "DNA_anim_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
39 
40 #include "BKE_action.h"
41 #include "BKE_curve.h"
42 #include "BKE_fcurve.h"
43 #include "BKE_main.h"
44 #include "BKE_report.h"
45 
46 #include "RNA_access.h"
47 #include "RNA_enum_types.h"
48 
49 #include "ED_anim_api.h"
50 #include "ED_keyframes_edit.h"
51 #include "ED_keyframing.h"
52 
53 /* This file contains code for various keyframe-editing tools which are 'destructive'
54  * (i.e. they will modify the order of the keyframes, and change the size of the array).
55  * While some of these tools may eventually be moved out into blenkernel, for now, it is
56  * fine to have these calls here.
57  *
58  * There are also a few tools here which cannot be easily coded for in the other system (yet).
59  * These may also be moved around at some point, but for now, they are best added here.
60  *
61  * - Joshua Leung, Dec 2008
62  */
63 
64 /* **************************************************** */
65 
71 void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc)
72 {
73  /* sanity check */
74  if (fcu == NULL) {
75  return;
76  }
77 
78  /* verify the index:
79  * 1) cannot be greater than the number of available keyframes
80  * 2) negative indices are for specifying a value from the end of the array
81  */
82  if (abs(index) >= fcu->totvert) {
83  return;
84  }
85  if (index < 0) {
86  index += fcu->totvert;
87  }
88 
89  /* Delete this keyframe */
90  memmove(
91  &fcu->bezt[index], &fcu->bezt[index + 1], sizeof(BezTriple) * (fcu->totvert - index - 1));
92  fcu->totvert--;
93 
94  if (fcu->totvert == 0) {
95  if (fcu->bezt) {
96  MEM_freeN(fcu->bezt);
97  }
98  fcu->bezt = NULL;
99  }
100 
101  /* recalc handles - only if it won't cause problems */
102  if (do_recalc) {
103  calchandles_fcurve(fcu);
104  }
105 }
106 
107 /* Delete selected keyframes in given F-Curve */
109 {
110  bool changed = false;
111 
112  if (fcu->bezt == NULL) { /* ignore baked curves */
113  return false;
114  }
115 
116  /* Delete selected BezTriples */
117  for (int i = 0; i < fcu->totvert; i++) {
118  if (fcu->bezt[i].f2 & SELECT) {
119  if (i == fcu->active_keyframe_index) {
121  }
122  memmove(&fcu->bezt[i], &fcu->bezt[i + 1], sizeof(BezTriple) * (fcu->totvert - i - 1));
123  fcu->totvert--;
124  i--;
125  changed = true;
126  }
127  }
128 
129  /* Free the array of BezTriples if there are not keyframes */
130  if (fcu->totvert == 0) {
131  clear_fcurve_keys(fcu);
132  }
133 
134  return changed;
135 }
136 
138 {
139  if (fcu->bezt) {
140  MEM_freeN(fcu->bezt);
141  }
142  fcu->bezt = NULL;
143 
144  fcu->totvert = 0;
145 }
146 
147 /* ---------------- */
148 
149 /* duplicate selected keyframes for the given F-Curve */
151 {
152  /* this can only work when there is an F-Curve, and also when there are some BezTriples */
153  if (ELEM(NULL, fcu, fcu->bezt)) {
154  return;
155  }
156 
157  for (int i = 0; i < fcu->totvert; i++) {
158  /* If a key is selected */
159  if (fcu->bezt[i].f2 & SELECT) {
160  /* Expand the list */
161  BezTriple *newbezt = MEM_callocN(sizeof(BezTriple) * (fcu->totvert + 1), "beztriple");
162 
163  memcpy(newbezt, fcu->bezt, sizeof(BezTriple) * (i + 1));
164  memcpy(newbezt + i + 1, fcu->bezt + i, sizeof(BezTriple));
165  memcpy(newbezt + i + 2, fcu->bezt + i + 1, sizeof(BezTriple) * (fcu->totvert - (i + 1)));
166  fcu->totvert++;
167 
168  /* reassign pointers... (free old, and add new) */
169  MEM_freeN(fcu->bezt);
170  fcu->bezt = newbezt;
171 
172  /* Unselect the current key */
173  BEZT_DESEL_ALL(&fcu->bezt[i]);
174  i++;
175 
176  /* Select the copied key */
177  BEZT_SEL_ALL(&fcu->bezt[i]);
178  }
179  }
180 }
181 
182 /* **************************************************** */
183 /* Various Tools */
184 
189 void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault)
190 {
191  FCurve *fcu = (FCurve *)ale->key_data;
192  BezTriple *old_bezts, *bezt, *beztn;
193  BezTriple *lastb;
194  int totCount, i;
195 
196  /* check if any points */
197  if ((fcu == NULL) || (fcu->bezt == NULL) || (fcu->totvert == 0) ||
198  (!cleardefault && fcu->totvert == 1)) {
199  return;
200  }
201 
202  /* make a copy of the old BezTriples, and clear F-Curve */
203  old_bezts = fcu->bezt;
204  totCount = fcu->totvert;
205  fcu->bezt = NULL;
206  fcu->totvert = 0;
207 
208  /* now insert first keyframe, as it should be ok */
209  bezt = old_bezts;
210  insert_bezt_fcurve(fcu, bezt, 0);
211  if (!(bezt->f2 & SELECT)) {
212  lastb = fcu->bezt;
213  lastb->f1 = lastb->f2 = lastb->f3 = 0;
214  }
215 
216  /* Loop through BezTriples, comparing them. Skip any that do
217  * not fit the criteria for "ok" points.
218  */
219  for (i = 1; i < totCount; i++) {
220  float prev[2], cur[2], next[2];
221 
222  /* get BezTriples and their values */
223  if (i < (totCount - 1)) {
224  beztn = (old_bezts + (i + 1));
225  next[0] = beztn->vec[1][0];
226  next[1] = beztn->vec[1][1];
227  }
228  else {
229  beztn = NULL;
230  next[0] = next[1] = 0.0f;
231  }
232  lastb = (fcu->bezt + (fcu->totvert - 1));
233  bezt = (old_bezts + i);
234 
235  /* get references for quicker access */
236  prev[0] = lastb->vec[1][0];
237  prev[1] = lastb->vec[1][1];
238  cur[0] = bezt->vec[1][0];
239  cur[1] = bezt->vec[1][1];
240 
241  if (!(bezt->f2 & SELECT)) {
242  insert_bezt_fcurve(fcu, bezt, 0);
243  lastb = (fcu->bezt + (fcu->totvert - 1));
244  lastb->f1 = lastb->f2 = lastb->f3 = 0;
245  continue;
246  }
247 
248  /* check if current bezt occurs at same time as last ok */
249  if (IS_EQT(cur[0], prev[0], thresh)) {
250  /* If there is a next beztriple, and if occurs at the same time, only insert
251  * if there is a considerable distance between the points, and also if the
252  * current is further away than the next one is to the previous.
253  */
254  if (beztn && (IS_EQT(cur[0], next[0], thresh)) && (IS_EQT(next[1], prev[1], thresh) == 0)) {
255  /* only add if current is further away from previous */
256  if (cur[1] > next[1]) {
257  if (IS_EQT(cur[1], prev[1], thresh) == 0) {
258  /* add new keyframe */
259  insert_bezt_fcurve(fcu, bezt, 0);
260  }
261  }
262  }
263  else {
264  /* only add if values are a considerable distance apart */
265  if (IS_EQT(cur[1], prev[1], thresh) == 0) {
266  /* add new keyframe */
267  insert_bezt_fcurve(fcu, bezt, 0);
268  }
269  }
270  }
271  else {
272  /* checks required are dependent on whether this is last keyframe or not */
273  if (beztn) {
274  /* does current have same value as previous and next? */
275  if (IS_EQT(cur[1], prev[1], thresh) == 0) {
276  /* add new keyframe */
277  insert_bezt_fcurve(fcu, bezt, 0);
278  }
279  else if (IS_EQT(cur[1], next[1], thresh) == 0) {
280  /* add new keyframe */
281  insert_bezt_fcurve(fcu, bezt, 0);
282  }
283  }
284  else {
285  /* add if value doesn't equal that of previous */
286  if (IS_EQT(cur[1], prev[1], thresh) == 0) {
287  /* add new keyframe */
288  insert_bezt_fcurve(fcu, bezt, 0);
289  }
290  }
291  }
292  }
293 
294  /* now free the memory used by the old BezTriples */
295  if (old_bezts) {
296  MEM_freeN(old_bezts);
297  }
298 
299  /* final step, if there is just one key in fcurve, check if it's
300  * the default value and if is, remove fcurve completely. */
301  if (cleardefault && fcu->totvert == 1) {
302  float default_value = 0.0f;
303  PointerRNA id_ptr, ptr;
304  PropertyRNA *prop;
305  RNA_id_pointer_create(ale->id, &id_ptr);
306 
307  /* get property to read from, and get value as appropriate */
308  if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
309  if (RNA_property_type(prop) == PROP_FLOAT) {
310  default_value = RNA_property_float_get_default_index(&ptr, prop, fcu->array_index);
311  }
312  }
313 
314  if (fcu->bezt->vec[1][1] == default_value) {
315  clear_fcurve_keys(fcu);
316 
317  /* check if curve is really unused and if it is, return signal for deletion */
318  if (BKE_fcurve_is_empty(fcu)) {
319  AnimData *adt = ale->adt;
320  ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
321  ale->key_data = NULL;
322  }
323  }
324  }
325 }
326 
327 /* ---------------- */
328 
329 /* Check if the keyframe interpolation type is supported */
330 static bool prepare_for_decimate(FCurve *fcu, int i)
331 {
332  switch (fcu->bezt[i].ipo) {
333  case BEZT_IPO_BEZ:
334  /* We do not need to do anything here as the keyframe already has the required setting.
335  */
336  return true;
337  case BEZT_IPO_LIN:
338  /* Convert to a linear bezt curve to be able to use the decimation algorithm. */
339  fcu->bezt[i].ipo = BEZT_IPO_BEZ;
340  fcu->bezt[i].h1 = HD_FREE;
341  fcu->bezt[i].h2 = HD_FREE;
342 
343  if (i != 0) {
344  float h1[3];
345  sub_v3_v3v3(h1, fcu->bezt[i - 1].vec[1], fcu->bezt[i].vec[1]);
346  mul_v3_fl(h1, 1.0f / 3.0f);
347  add_v3_v3(h1, fcu->bezt[i].vec[1]);
348  copy_v3_v3(fcu->bezt[i].vec[0], h1);
349  }
350 
351  if (i + 1 != fcu->totvert) {
352  float h2[3];
353  sub_v3_v3v3(h2, fcu->bezt[i + 1].vec[1], fcu->bezt[i].vec[1]);
354  mul_v3_fl(h2, 1.0f / 3.0f);
355  add_v3_v3(h2, fcu->bezt[i].vec[1]);
356  copy_v3_v3(fcu->bezt[i].vec[2], h2);
357  }
358  return true;
359  default:
360  /* These are unsupported. */
361  return false;
362  }
363 }
364 
365 /* Decimate the given curve segment. */
367  int bezt_segment_start_idx,
368  int bezt_segment_len,
369  float remove_ratio,
370  float error_sq_max)
371 {
372  int selected_len = bezt_segment_len;
373 
374  /* Make sure that we can remove the start/end point of the segment if they
375  * are not the start/end point of the curve. BKE_curve_decimate_bezt_array
376  * has a check that prevents removal of the first and last index in the
377  * passed array. */
378  if (bezt_segment_len + bezt_segment_start_idx != fcu->totvert &&
379  prepare_for_decimate(fcu, bezt_segment_len + bezt_segment_start_idx)) {
380  bezt_segment_len++;
381  }
382  if (bezt_segment_start_idx != 0 && prepare_for_decimate(fcu, bezt_segment_start_idx - 1)) {
383  bezt_segment_start_idx--;
384  bezt_segment_len++;
385  }
386 
387  const int target_fcurve_verts = ceil(bezt_segment_len - selected_len * remove_ratio);
388 
389  BKE_curve_decimate_bezt_array(&fcu->bezt[bezt_segment_start_idx],
390  bezt_segment_len,
391  12, /* The actual resolution displayed in the viewport is dynamic
392  * so we just pick a value that preserves the curve shape. */
393  false,
394  SELECT,
396  error_sq_max,
397  target_fcurve_verts);
398 }
399 
407 bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
408 {
409  FCurve *fcu = (FCurve *)ale->key_data;
410 
411  /* Check if the curve actually has any points */
412  if (fcu == NULL || fcu->bezt == NULL || fcu->totvert == 0) {
413  return true;
414  }
415 
416  BezTriple *old_bezts = fcu->bezt;
417 
418  /* Only decimate the individual selected curve segments. */
419  int bezt_segment_start_idx = 0;
420  int bezt_segment_len = 0;
421 
422  bool selected;
423  bool can_decimate_all_selected = true;
424  bool in_segment = false;
425 
426  for (int i = 0; i < fcu->totvert; i++) {
427  selected = fcu->bezt[i].f2 & SELECT;
428  /* Make sure that the temp flag is unset as we use it to determine what to remove. */
429  fcu->bezt[i].f2 &= ~BEZT_FLAG_TEMP_TAG;
430 
431  if (selected && !prepare_for_decimate(fcu, i)) {
432  /* This keyframe is not supported, treat them as if they were unselected. */
433  selected = false;
434  can_decimate_all_selected = false;
435  }
436 
437  if (selected) {
438  if (!in_segment) {
439  bezt_segment_start_idx = i;
440  in_segment = true;
441  }
442  bezt_segment_len++;
443  }
444  else if (in_segment) {
445  /* If the curve point is not selected then we have reached the end of the selected curve
446  * segment. */
448  fcu, bezt_segment_start_idx, bezt_segment_len, remove_ratio, error_sq_max);
449  in_segment = false;
450  bezt_segment_len = 0;
451  }
452  }
453 
454  /* Did the segment run to the end of the curve? */
455  if (in_segment) {
457  fcu, bezt_segment_start_idx, bezt_segment_len, remove_ratio, error_sq_max);
458  }
459 
460  uint old_totvert = fcu->totvert;
461  fcu->bezt = NULL;
462  fcu->totvert = 0;
463 
464  for (int i = 0; i < old_totvert; i++) {
465  BezTriple *bezt = (old_bezts + i);
466  if ((bezt->f2 & BEZT_FLAG_TEMP_TAG) == 0) {
467  insert_bezt_fcurve(fcu, bezt, 0);
468  }
469  }
470  /* now free the memory used by the old BezTriples */
471  if (old_bezts) {
472  MEM_freeN(old_bezts);
473  }
474 
475  return can_decimate_all_selected;
476 }
477 
478 /* ---------------- */
479 
480 /* temp struct used for smooth_fcurve */
481 typedef struct tSmooth_Bezt {
482  float *h1, *h2, *h3; /* bezt->vec[0,1,2][1] */
483  float y1, y2, y3; /* averaged before/new/after y-values */
485 
486 /* Use a weighted moving-means method to reduce intensity of fluctuations */
487 /* TODO: introduce scaling factor for weighting falloff */
489 {
490  int totSel = 0;
491 
492  if (fcu->bezt == NULL) {
493  return;
494  }
495 
496  /* first loop through - count how many verts are selected */
497  BezTriple *bezt = fcu->bezt;
498  for (int i = 0; i < fcu->totvert; i++, bezt++) {
499  if (BEZT_ISSEL_ANY(bezt)) {
500  totSel++;
501  }
502  }
503 
504  /* if any points were selected, allocate tSmooth_Bezt points to work on */
505  if (totSel >= 3) {
506  tSmooth_Bezt *tarray, *tsb;
507 
508  /* allocate memory in one go */
509  tsb = tarray = MEM_callocN(totSel * sizeof(tSmooth_Bezt), "tSmooth_Bezt Array");
510 
511  /* populate tarray with data of selected points */
512  bezt = fcu->bezt;
513  for (int i = 0, x = 0; (i < fcu->totvert) && (x < totSel); i++, bezt++) {
514  if (BEZT_ISSEL_ANY(bezt)) {
515  /* tsb simply needs pointer to vec, and index */
516  tsb->h1 = &bezt->vec[0][1];
517  tsb->h2 = &bezt->vec[1][1];
518  tsb->h3 = &bezt->vec[2][1];
519 
520  /* advance to the next tsb to populate */
521  if (x < totSel - 1) {
522  tsb++;
523  }
524  else {
525  break;
526  }
527  }
528  }
529 
530  /* calculate the new smoothed F-Curve's with weighted averages:
531  * - this is done with two passes to avoid progressive corruption errors
532  * - uses 5 points for each operation (which stores in the relevant handles)
533  * - previous: w/a ratio = 3:5:2:1:1
534  * - next: w/a ratio = 1:1:2:5:3
535  */
536 
537  /* round 1: calculate smoothing deltas and new values */
538  tsb = tarray;
539  for (int i = 0; i < totSel; i++, tsb++) {
540  /* Don't touch end points (otherwise, curves slowly explode,
541  * as we don't have enough data there). */
542  if (ELEM(i, 0, (totSel - 1)) == 0) {
543  const tSmooth_Bezt *tP1 = tsb - 1;
544  const tSmooth_Bezt *tP2 = (i - 2 > 0) ? (tsb - 2) : (NULL);
545  const tSmooth_Bezt *tN1 = tsb + 1;
546  const tSmooth_Bezt *tN2 = (i + 2 < totSel) ? (tsb + 2) : (NULL);
547 
548  const float p1 = *tP1->h2;
549  const float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2);
550  const float c1 = *tsb->h2;
551  const float n1 = *tN1->h2;
552  const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2);
553 
554  /* calculate previous and next, then new position by averaging these */
555  tsb->y1 = (3 * p2 + 5 * p1 + 2 * c1 + n1 + n2) / 12;
556  tsb->y3 = (p2 + p1 + 2 * c1 + 5 * n1 + 3 * n2) / 12;
557 
558  tsb->y2 = (tsb->y1 + tsb->y3) / 2;
559  }
560  }
561 
562  /* round 2: apply new values */
563  tsb = tarray;
564  for (int i = 0; i < totSel; i++, tsb++) {
565  /* don't touch end points, as their values weren't touched above */
566  if (ELEM(i, 0, (totSel - 1)) == 0) {
567  /* y2 takes the average of the 2 points */
568  *tsb->h2 = tsb->y2;
569 
570  /* handles are weighted between their original values and the averaged values */
571  *tsb->h1 = ((*tsb->h1) * 0.7f) + (tsb->y1 * 0.3f);
572  *tsb->h3 = ((*tsb->h3) * 0.7f) + (tsb->y3 * 0.3f);
573  }
574  }
575 
576  /* free memory required for tarray */
577  MEM_freeN(tarray);
578  }
579 
580  /* recalculate handles */
581  calchandles_fcurve(fcu);
582 }
583 
584 /* ---------------- */
585 
586 /* little cache for values... */
587 typedef struct TempFrameValCache {
588  float frame, val;
590 
591 /* Evaluates the curves between each selected keyframe on each frame, and keys the value */
593 {
594  BezTriple *bezt, *start = NULL, *end = NULL;
595  TempFrameValCache *value_cache, *fp;
596  int sfra, range;
597  int i, n;
598 
599  if (fcu->bezt == NULL) { /* ignore baked */
600  return;
601  }
602 
603  /* find selected keyframes... once pair has been found, add keyframes */
604  for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
605  /* check if selected, and which end this is */
606  if (BEZT_ISSEL_ANY(bezt)) {
607  if (start) {
608  /* If next bezt is also selected, don't start sampling yet,
609  * but instead wait for that one to reconsider, to avoid
610  * changing the curve when sampling consecutive segments
611  * (T53229)
612  */
613  if (i < fcu->totvert - 1) {
614  BezTriple *next = &fcu->bezt[i + 1];
615  if (BEZT_ISSEL_ANY(next)) {
616  continue;
617  }
618  }
619 
620  /* set end */
621  end = bezt;
622 
623  /* cache values then add keyframes using these values, as adding
624  * keyframes while sampling will affect the outcome...
625  * - only start sampling+adding from index=1, so that we don't overwrite original keyframe
626  */
627  range = (int)(ceil(end->vec[1][0] - start->vec[1][0]));
628  sfra = (int)(floor(start->vec[1][0]));
629 
630  if (range) {
631  value_cache = MEM_callocN(sizeof(TempFrameValCache) * range, "IcuFrameValCache");
632 
633  /* sample values */
634  for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
635  fp->frame = (float)(sfra + n);
636  fp->val = evaluate_fcurve(fcu, fp->frame);
637  }
638 
639  /* add keyframes with these, tagging as 'breakdowns' */
640  for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
641  insert_vert_fcurve(fcu, fp->frame, fp->val, BEZT_KEYTYPE_BREAKDOWN, 1);
642  }
643 
644  /* free temp cache */
645  MEM_freeN(value_cache);
646 
647  /* as we added keyframes, we need to compensate so that bezt is at the right place */
648  bezt = fcu->bezt + i + range - 1;
649  i += (range - 1);
650  }
651 
652  /* the current selection island has ended, so start again from scratch */
653  start = NULL;
654  end = NULL;
655  }
656  else {
657  /* just set start keyframe */
658  start = bezt;
659  end = NULL;
660  }
661  }
662  }
663 
664  /* recalculate channel's handles? */
665  calchandles_fcurve(fcu);
666 }
667 
668 /* **************************************************** */
669 /* Copy/Paste Tools:
670  * - The copy/paste buffer currently stores a set of temporary F-Curves containing only the
671  * keyframes that were selected in each of the original F-Curves.
672  * - All pasted frames are offset by the same amount.
673  * This is calculated as the difference in the times of the current frame and the
674  * 'first keyframe' (i.e. the earliest one in all channels).
675  * - The earliest frame is calculated per copy operation.
676  */
677 
678 /* globals for copy/paste data (like for other copy/paste buffers) */
680 static float animcopy_firstframe = 999999999.0f;
681 static float animcopy_lastframe = -999999999.0f;
682 static float animcopy_cfra = 0.0;
683 
684 /* datatype for use in copy/paste buffer */
685 typedef struct tAnimCopybufItem {
687 
688  ID *id; /* ID which owns the curve */
689  bActionGroup *grp; /* Action Group */
690  char *rna_path; /* RNA-Path */
691  int array_index; /* array index */
692 
693  int totvert; /* number of keyframes stored for this channel */
694  BezTriple *bezt; /* keyframes in buffer */
695 
696  short id_type; /* Result of GS(id->name)*/
697  bool is_bone; /* special flag for armature bones */
699 
700 /* This function frees any MEM_calloc'ed copy/paste buffer data */
702 {
703  tAnimCopybufItem *aci, *acn;
704 
705  /* free each buffer element */
706  for (aci = animcopybuf.first; aci; aci = acn) {
707  acn = aci->next;
708 
709  /* free keyframes */
710  if (aci->bezt) {
711  MEM_freeN(aci->bezt);
712  }
713 
714  /* free RNA-path */
715  if (aci->rna_path) {
716  MEM_freeN(aci->rna_path);
717  }
718 
719  /* free ourself */
720  BLI_freelinkN(&animcopybuf, aci);
721  }
722 
723  /* restore initial state */
725  animcopy_firstframe = 999999999.0f;
726  animcopy_lastframe = -999999999.0f;
727 }
728 
729 /* ------------------- */
730 
731 /* This function adds data to the keyframes copy/paste buffer, freeing existing data first */
733 {
734  bAnimListElem *ale;
735  Scene *scene = ac->scene;
736 
737  /* clear buffer first */
739 
740  /* assume that each of these is an F-Curve */
741  for (ale = anim_data->first; ale; ale = ale->next) {
742  FCurve *fcu = (FCurve *)ale->key_data;
743  tAnimCopybufItem *aci;
744  BezTriple *bezt, *nbezt, *newbuf;
745  int i;
746 
747  /* firstly, check if F-Curve has any selected keyframes
748  * - skip if no selected keyframes found (so no need to create unnecessary copy-buffer data)
749  * - this check should also eliminate any problems associated with using sample-data
750  */
753  continue;
754  }
755 
756  /* init copybuf item info */
757  aci = MEM_callocN(sizeof(tAnimCopybufItem), "AnimCopybufItem");
758  aci->id = ale->id;
759  aci->id_type = GS(ale->id->name);
760  aci->grp = fcu->grp;
761  aci->rna_path = MEM_dupallocN(fcu->rna_path);
762  aci->array_index = fcu->array_index;
763 
764  /* Detect if this is a bone. We do that here rather than during pasting because ID pointers
765  * will get invalidated if we undo.
766  * Storing the relevant information here helps avoiding crashes if we undo-repaste. */
767  if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) {
768  Object *ob = (Object *)aci->id;
769 
770  char *bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones[");
771  if (bone_name) {
772  bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
773  MEM_freeN(bone_name);
774 
775  if (pchan) {
776  aci->is_bone = true;
777  }
778  }
779  }
780 
781  BLI_addtail(&animcopybuf, aci);
782 
783  /* add selected keyframes to buffer */
784  /* TODO: currently, we resize array every time we add a new vert -
785  * this works ok as long as it is assumed only a few keys are copied */
786  for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
787  if (BEZT_ISSEL_ANY(bezt)) {
788  /* add to buffer */
789  newbuf = MEM_callocN(sizeof(BezTriple) * (aci->totvert + 1), "copybuf beztriple");
790 
791  /* assume that since we are just re-sizing the array, just copy all existing data across */
792  if (aci->bezt) {
793  memcpy(newbuf, aci->bezt, sizeof(BezTriple) * (aci->totvert));
794  }
795 
796  /* copy current beztriple across too */
797  nbezt = &newbuf[aci->totvert];
798  *nbezt = *bezt;
799 
800  /* ensure copy buffer is selected so pasted keys are selected */
801  BEZT_SEL_ALL(nbezt);
802 
803  /* free old array and set the new */
804  if (aci->bezt) {
805  MEM_freeN(aci->bezt);
806  }
807  aci->bezt = newbuf;
808  aci->totvert++;
809 
810  /* check if this is the earliest frame encountered so far */
811  if (bezt->vec[1][0] < animcopy_firstframe) {
812  animcopy_firstframe = bezt->vec[1][0];
813  }
814  if (bezt->vec[1][0] > animcopy_lastframe) {
815  animcopy_lastframe = bezt->vec[1][0];
816  }
817  }
818  }
819  }
820 
821  /* check if anything ended up in the buffer */
823  return -1;
824  }
825 
826  /* in case 'relative' paste method is used */
828 
829  /* everything went fine */
830  return 0;
831 }
832 
833 static void flip_names(tAnimCopybufItem *aci, char **name)
834 {
835  if (aci->is_bone) {
836  char *str_start;
837  if ((str_start = strstr(aci->rna_path, "pose.bones["))) {
838  /* ninja coding, try to change the name */
839  char bname_new[MAX_VGROUP_NAME];
840  char *str_iter, *str_end;
841  int length, prefix_l, postfix_l;
842 
843  str_start += 12;
844  prefix_l = str_start - aci->rna_path;
845 
846  str_end = strchr(str_start, '\"');
847 
848  length = str_end - str_start;
849  postfix_l = strlen(str_end);
850 
851  /* more ninja stuff, temporary substitute with NULL terminator */
852  str_start[length] = 0;
853  BLI_string_flip_side_name(bname_new, str_start, false, sizeof(bname_new));
854  str_start[length] = '\"';
855 
856  str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1),
857  "flipped_path");
858 
859  BLI_strncpy(str_iter, aci->rna_path, prefix_l + 1);
860  str_iter += prefix_l;
861  BLI_strncpy(str_iter, bname_new, length + 1);
862  str_iter += length;
863  BLI_strncpy(str_iter, str_end, postfix_l + 1);
864  str_iter[postfix_l] = '\0';
865  }
866  }
867 }
868 
869 /* ------------------- */
870 
871 /* most strict method: exact matches only */
873  const short from_single,
874  const short to_simple,
875  bool flip)
876 {
877  tAnimCopybufItem *aci;
878 
879  for (aci = animcopybuf.first; aci; aci = aci->next) {
880  if (to_simple || (aci->rna_path && fcu->rna_path)) {
881  if (!to_simple && flip && aci->is_bone && fcu->rna_path) {
882  if ((from_single) || (aci->array_index == fcu->array_index)) {
883  char *name = NULL;
884  flip_names(aci, &name);
885  if (STREQ(name, fcu->rna_path)) {
886  MEM_freeN(name);
887  break;
888  }
889  MEM_freeN(name);
890  }
891  }
892  else if (to_simple || STREQ(aci->rna_path, fcu->rna_path)) {
893  if ((from_single) || (aci->array_index == fcu->array_index)) {
894  break;
895  }
896  }
897  }
898  }
899 
900  return aci;
901 }
902 
903 /* medium match strictness: path match only (i.e. ignore ID) */
905  FCurve *fcu,
906  const short from_single,
907  const short UNUSED(to_simple))
908 {
909  tAnimCopybufItem *aci;
910 
911  for (aci = animcopybuf.first; aci; aci = aci->next) {
912  /* check that paths exist */
913  if (aci->rna_path && fcu->rna_path) {
914  /* find the property of the fcurve and compare against the end of the tAnimCopybufItem
915  * more involved since it needs to do path lookups.
916  * This is not 100% reliable since the user could be editing the curves on a path that wont
917  * resolve, or a bone could be renamed after copying for eg. but in normal copy & paste
918  * this should work out ok.
919  */
920  if (BLI_findindex(which_libbase(bmain, aci->id_type), aci->id) == -1) {
921  /* pedantic but the ID could have been removed, and beats crashing! */
922  printf("paste_animedit_keys: error ID has been removed!\n");
923  }
924  else {
925  PointerRNA id_ptr, rptr;
926  PropertyRNA *prop;
927 
928  RNA_id_pointer_create(aci->id, &id_ptr);
929 
930  if (RNA_path_resolve_property(&id_ptr, aci->rna_path, &rptr, &prop)) {
931  const char *identifier = RNA_property_identifier(prop);
932  int len_id = strlen(identifier);
933  int len_path = strlen(fcu->rna_path);
934  if (len_id <= len_path) {
935  /* note, paths which end with "] will fail with this test - Animated ID Props */
936  if (STREQ(identifier, fcu->rna_path + (len_path - len_id))) {
937  if ((from_single) || (aci->array_index == fcu->array_index)) {
938  break;
939  }
940  }
941  }
942  }
943  else {
944  printf("paste_animedit_keys: failed to resolve path id:%s, '%s'!\n",
945  aci->id->name,
946  aci->rna_path);
947  }
948  }
949  }
950  }
951 
952  return aci;
953 }
954 
955 /* least strict matching heuristic: indices only */
957  const short from_single,
958  const short UNUSED(to_simple))
959 {
960  tAnimCopybufItem *aci;
961 
962  for (aci = animcopybuf.first; aci; aci = aci->next) {
963  /* check that paths exist */
964  if ((from_single) || (aci->array_index == fcu->array_index)) {
965  break;
966  }
967  }
968 
969  return aci;
970 }
971 
972 /* ................ */
973 
975 {
976  if (aci->is_bone) {
977  const size_t slength = strlen(aci->rna_path);
978  bool flip = false;
979  if (BLI_strn_endswith(aci->rna_path, "location", slength) && aci->array_index == 0) {
980  flip = true;
981  }
982  else if (BLI_strn_endswith(aci->rna_path, "rotation_quaternion", slength) &&
983  ELEM(aci->array_index, 2, 3)) {
984  flip = true;
985  }
986  else if (BLI_strn_endswith(aci->rna_path, "rotation_euler", slength) &&
987  ELEM(aci->array_index, 1, 2)) {
988  flip = true;
989  }
990  else if (BLI_strn_endswith(aci->rna_path, "rotation_axis_angle", slength) &&
991  ELEM(aci->array_index, 2, 3)) {
992  flip = true;
993  }
994 
995  if (flip) {
996  bezt->vec[0][1] = -bezt->vec[0][1];
997  bezt->vec[1][1] = -bezt->vec[1][1];
998  bezt->vec[2][1] = -bezt->vec[2][1];
999  }
1000  }
1001 }
1002 
1003 /* helper for paste_animedit_keys() - performs the actual pasting */
1005  FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode, bool flip)
1006 {
1007  BezTriple *bezt;
1008  int i;
1009 
1010  /* First de-select existing FCurve's keyframes */
1011  for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
1013  }
1014 
1015  /* mix mode with existing data */
1016  switch (merge_mode) {
1018  /* do-nothing */
1019  break;
1020 
1022  /* remove all keys */
1023  clear_fcurve_keys(fcu);
1024  break;
1025 
1028  float f_min;
1029  float f_max;
1030 
1031  if (merge_mode == KEYFRAME_PASTE_MERGE_OVER_RANGE) {
1032  f_min = aci->bezt[0].vec[1][0] + offset;
1033  f_max = aci->bezt[aci->totvert - 1].vec[1][0] + offset;
1034  }
1035  else { /* Entire Range */
1036  f_min = animcopy_firstframe + offset;
1037  f_max = animcopy_lastframe + offset;
1038  }
1039 
1040  /* remove keys in range */
1041  if (f_min < f_max) {
1042  /* select verts in range for removal */
1043  for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
1044  if ((f_min < bezt[0].vec[1][0]) && (bezt[0].vec[1][0] < f_max)) {
1045  bezt->f2 |= SELECT;
1046  }
1047  }
1048 
1049  /* remove frames in the range */
1050  delete_fcurve_keys(fcu);
1051  }
1052  break;
1053  }
1054  }
1055 
1056  /* just start pasting, with the first keyframe on the current frame, and so on */
1057  for (i = 0, bezt = aci->bezt; i < aci->totvert; i++, bezt++) {
1058  /* temporarily apply offset to src beztriple while copying */
1059  if (flip) {
1061  }
1062 
1063  bezt->vec[0][0] += offset;
1064  bezt->vec[1][0] += offset;
1065  bezt->vec[2][0] += offset;
1066 
1067  /* insert the keyframe
1068  * NOTE: we do not want to inherit handles from existing keyframes in this case!
1069  */
1070 
1072 
1073  /* un-apply offset from src beztriple after copying */
1074  bezt->vec[0][0] -= offset;
1075  bezt->vec[1][0] -= offset;
1076  bezt->vec[2][0] -= offset;
1077 
1078  if (flip) {
1080  }
1081  }
1082 
1083  /* recalculate F-Curve's handles? */
1084  calchandles_fcurve(fcu);
1085 }
1086 
1087 /* ------------------- */
1088 
1091  "START",
1092  0,
1093  "Frame Start",
1094  "Paste keys starting at current frame"},
1095  {KEYFRAME_PASTE_OFFSET_CFRA_END, "END", 0, "Frame End", "Paste keys ending at current frame"},
1097  "RELATIVE",
1098  0,
1099  "Frame Relative",
1100  "Paste keys relative to the current frame when copying"},
1101  {KEYFRAME_PASTE_OFFSET_NONE, "NONE", 0, "No Offset", "Paste keys from original time"},
1102  {0, NULL, 0, NULL, NULL},
1103 };
1104 
1106  {KEYFRAME_PASTE_MERGE_MIX, "MIX", 0, "Mix", "Overlay existing with new keys"},
1107  {KEYFRAME_PASTE_MERGE_OVER, "OVER_ALL", 0, "Overwrite All", "Replace all keys"},
1109  "OVER_RANGE",
1110  0,
1111  "Overwrite Range",
1112  "Overwrite keys in pasted range"},
1114  "OVER_RANGE_ALL",
1115  0,
1116  "Overwrite Entire Range",
1117  "Overwrite keys in pasted range, using the range of all copied keys"},
1118  {0, NULL, 0, NULL, NULL},
1119 };
1120 
1127  ListBase *anim_data,
1128  const eKeyPasteOffset offset_mode,
1129  const eKeyMergeMode merge_mode,
1130  bool flip)
1131 {
1132  bAnimListElem *ale;
1133 
1134  const Scene *scene = (ac->scene);
1135 
1136  const bool from_single = BLI_listbase_is_single(&animcopybuf);
1137  const bool to_simple = BLI_listbase_is_single(anim_data);
1138 
1139  float offset = 0.0f;
1140  int pass;
1141 
1142  /* check if buffer is empty */
1144  BKE_report(ac->reports, RPT_ERROR, "No animation data in buffer to paste");
1145  return -1;
1146  }
1147 
1148  if (BLI_listbase_is_empty(anim_data)) {
1149  BKE_report(ac->reports, RPT_ERROR, "No selected F-Curves to paste into");
1150  return -1;
1151  }
1152 
1153  /* methods of offset */
1154  switch (offset_mode) {
1156  offset = (float)(CFRA - animcopy_firstframe);
1157  break;
1159  offset = (float)(CFRA - animcopy_lastframe);
1160  break;
1162  offset = (float)(CFRA - animcopy_cfra);
1163  break;
1165  offset = 0.0f;
1166  break;
1167  }
1168 
1169  if (from_single && to_simple) {
1170  /* 1:1 match, no tricky checking, just paste */
1171  FCurve *fcu;
1172  tAnimCopybufItem *aci;
1173 
1174  ale = anim_data->first;
1175  fcu = (FCurve *)ale->data; /* destination F-Curve */
1176  aci = animcopybuf.first;
1177 
1178  paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, false);
1179  ale->update |= ANIM_UPDATE_DEFAULT;
1180  }
1181  else {
1182  /* from selected channels
1183  * This "passes" system aims to try to find "matching" channels to paste keyframes
1184  * into with increasingly loose matching heuristics. The process finishes when at least
1185  * one F-Curve has been pasted into.
1186  */
1187  for (pass = 0; pass < 3; pass++) {
1188  uint totmatch = 0;
1189 
1190  for (ale = anim_data->first; ale; ale = ale->next) {
1191  /* Find buffer item to paste from:
1192  * - If names don't matter (i.e. only 1 channel in buffer), don't check id/group
1193  * - If names do matter, only check if id-type is ok for now
1194  * (group check is not that important).
1195  * - Most importantly, rna-paths should match (array indices are unimportant for now)
1196  */
1197  AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1198  FCurve *fcu = (FCurve *)ale->data; /* destination F-Curve */
1199  tAnimCopybufItem *aci = NULL;
1200 
1201  switch (pass) {
1202  case 0:
1203  /* most strict, must be exact path match data_path & index */
1204  aci = pastebuf_match_path_full(fcu, from_single, to_simple, flip);
1205  break;
1206 
1207  case 1:
1208  /* less strict, just compare property names */
1209  aci = pastebuf_match_path_property(ac->bmain, fcu, from_single, to_simple);
1210  break;
1211 
1212  case 2:
1213  /* Comparing properties gave no results, so just do index comparisons */
1214  aci = pastebuf_match_index_only(fcu, from_single, to_simple);
1215  break;
1216  }
1217 
1218  /* copy the relevant data from the matching buffer curve */
1219  if (aci) {
1220  totmatch++;
1221 
1222  if (adt) {
1223  ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
1224  paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
1225  ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
1226  }
1227  else {
1228  paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
1229  }
1230  }
1231 
1232  ale->update |= ANIM_UPDATE_DEFAULT;
1233  }
1234 
1235  /* don't continue if some fcurves were pasted */
1236  if (totmatch) {
1237  break;
1238  }
1239  }
1240  }
1241 
1242  ANIM_animdata_update(ac, anim_data);
1243 
1244  return 0;
1245 }
1246 
1247 /* **************************************************** */
typedef float(TangentPoint)[2]
Blender kernel action and pose functionality.
struct bPoseChannel * BKE_pose_channel_find_name(const struct bPose *pose, const char *name)
unsigned int BKE_curve_decimate_bezt_array(struct BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu, const bool is_cyclic, const char flag_test, const char flag_set, const float error_sq_max, const unsigned int error_target_len)
void BKE_fcurve_active_keyframe_set(struct FCurve *fcu, const struct BezTriple *active_bezt)
float evaluate_fcurve(struct FCurve *fcu, float evaltime)
Definition: fcurve.c:2186
bool BKE_fcurve_is_empty(struct FCurve *fcu)
Definition: fcurve.c:2250
void calchandles_fcurve(struct FCurve *fcu)
Definition: fcurve.c:1391
struct ListBase * which_libbase(struct Main *bmain, short type)
Definition: main.c:447
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:281
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void void BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
Definition: BLI_listbase.h:120
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t length) ATTR_NONNULL()
Definition: string.c:1017
char * BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict prefix) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:432
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
void BLI_string_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len)
Definition: string_utils.c:159
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED(x)
#define ELEM(...)
#define IS_EQT(a, b, c)
#define STREQ(a, b)
@ ID_OB
Definition: DNA_ID_enums.h:59
@ INSERTKEY_OVERWRITE_FULL
#define BEZT_SEL_ALL(bezt)
#define BEZT_ISSEL_ANY(bezt)
#define BEZT_DESEL_ALL(bezt)
@ HD_FREE
@ BEZT_IPO_BEZ
@ BEZT_IPO_LIN
@ BEZT_FLAG_TEMP_TAG
@ BEZT_KEYTYPE_BREAKDOWN
Object is a sort of wrapper for general info.
#define MAX_VGROUP_NAME
@ OB_ARMATURE
#define CFRA
#define ANIM_UPDATE_DEFAULT
Definition: ED_anim_api.h:281
eKeyMergeMode
@ KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL
@ KEYFRAME_PASTE_MERGE_OVER_RANGE
@ KEYFRAME_PASTE_MERGE_OVER
@ KEYFRAME_PASTE_MERGE_MIX
eKeyPasteOffset
@ KEYFRAME_PASTE_OFFSET_NONE
@ KEYFRAME_PASTE_OFFSET_CFRA_END
@ KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE
@ KEYFRAME_PASTE_OFFSET_CFRA_START
@ BEZT_OK_SELECTED
Read Guarded memory(de)allocation.
@ PROP_FLOAT
Definition: RNA_types.h:75
void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *fcu)
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
Definition: anim_deps.c:330
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
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
#define SELECT
Scene scene
#define GS(x)
Definition: iris.c:241
short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode, bool flip)
struct tSmooth_Bezt tSmooth_Bezt
static float animcopy_cfra
void duplicate_fcurve_keys(FCurve *fcu)
static bool prepare_for_decimate(FCurve *fcu, int i)
const EnumPropertyItem rna_enum_keyframe_paste_offset_items[]
short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data, const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip)
static void flip_names(tAnimCopybufItem *aci, char **name)
bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
static tAnimCopybufItem * pastebuf_match_path_property(Main *bmain, FCurve *fcu, const short from_single, const short UNUSED(to_simple))
struct tAnimCopybufItem tAnimCopybufItem
const EnumPropertyItem rna_enum_keyframe_paste_merge_items[]
void sample_fcurve(FCurve *fcu)
void clear_fcurve_keys(FCurve *fcu)
struct TempFrameValCache TempFrameValCache
static void decimate_fcurve_segment(FCurve *fcu, int bezt_segment_start_idx, int bezt_segment_len, float remove_ratio, float error_sq_max)
void smooth_fcurve(FCurve *fcu)
void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc)
void ANIM_fcurves_copybuf_free(void)
static void do_curve_mirror_flippping(tAnimCopybufItem *aci, BezTriple *bezt)
static ListBase animcopybuf
bool delete_fcurve_keys(FCurve *fcu)
static float animcopy_firstframe
static tAnimCopybufItem * pastebuf_match_path_full(FCurve *fcu, const short from_single, const short to_simple, bool flip)
void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault)
static tAnimCopybufItem * pastebuf_match_index_only(FCurve *fcu, const short from_single, const short UNUSED(to_simple))
static float animcopy_lastframe
int insert_vert_fcurve(FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag)
Definition: keyframing.c:547
int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
Definition: keyframing.c:403
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static ulong * next
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:122
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1145
float RNA_property_float_get_default_index(PointerRNA *ptr, PropertyRNA *prop, int index)
Definition: rna_access.c:3286
PropertyType RNA_property_type(PropertyRNA *prop)
Definition: rna_access.c:1155
bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition: rna_access.c:5434
float vec[3][3]
bActionGroup * grp
char * rna_path
BezTriple * bezt
int array_index
unsigned int totvert
int active_keyframe_index
Definition: DNA_ID.h:273
char name[66]
Definition: DNA_ID.h:283
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
struct bPose * pose
struct Scene * scene
Definition: ED_anim_api.h:97
struct ReportList * reports
Definition: ED_anim_api.h:108
struct Main * bmain
Definition: ED_anim_api.h:95
struct bAnimListElem * next
Definition: ED_anim_api.h:135
void * key_data
Definition: ED_anim_api.h:154
struct AnimData * adt
Definition: ED_anim_api.h:170
struct ID * id
Definition: ED_anim_api.h:168
struct tAnimCopybufItem * prev
bActionGroup * grp
struct tAnimCopybufItem * next
__forceinline const avxi abs(const avxi &a)
Definition: util_avxi.h:186
ccl_device_inline float2 floor(const float2 &a)
ccl_device_inline float3 ceil(const float3 &a)
PointerRNA * ptr
Definition: wm_files.c:3157