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