Blender V5.0
blenkernel/intern/fcurve.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors, Joshua Leung. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cfloat>
10#include <cmath>
11#include <cstddef>
12#include <cstdio>
13#include <cstring>
14
15#include "MEM_guardedalloc.h"
16
17#include "ANIM_action.hh"
18
19#include "DNA_action_types.h"
20#include "DNA_anim_types.h"
21
22#include "BLI_easing.h"
23#include "BLI_ghash.h"
24#include "BLI_listbase.h"
25#include "BLI_math_vector.h"
27#include "BLI_rect.h"
28#include "BLI_sort_utils.h"
29#include "BLI_string.h"
30#include "BLI_string_utils.hh"
31#include "BLI_task.hh"
32
33#include "BLT_translation.hh"
34
35#include "BKE_anim_data.hh"
36#include "BKE_animsys.h"
37#include "BKE_context.hh"
38#include "BKE_curve.hh"
39#include "BKE_fcurve.hh"
40#include "BKE_fcurve_driver.h"
41#include "BKE_global.hh"
42#include "BKE_idprop.hh"
43#include "BKE_lib_query.hh"
44#include "BKE_nla.hh"
45
46#include "BLO_read_write.hh"
47
48#include "RNA_access.hh"
49#include "RNA_path.hh"
50
51#include "CLG_log.h"
52
53#define SMALL -1.0e-10
54#define SELECT 1
55
56static CLG_LogRef LOG = {"anim.fcurve"};
57
58/* -------------------------------------------------------------------- */
61
63{
64 FCurve *fcu = MEM_callocN<FCurve>(__func__);
65 return fcu;
66}
67
69
70/* -------------------------------------------------------------------- */
73
75{
76 if (fcu == nullptr) {
77 return;
78 }
79
80 /* Free curve data. */
81 MEM_SAFE_FREE(fcu->bezt);
82 MEM_SAFE_FREE(fcu->fpt);
83
84 /* Free RNA-path, as this were allocated when getting the path string. */
86
87 /* Free extra data - i.e. modifiers, and driver. */
90
91 /* Free the f-curve itself. */
92 MEM_freeN(fcu);
93}
94
96{
97 /* Sanity check. */
98 if (list == nullptr) {
99 return;
100 }
101
102 /* Free data, no need to call #BLI_remlink before freeing each curve,
103 * as we store reference to next, and freeing only touches the curve it's given. */
104 FCurve *fcn = nullptr;
105 for (FCurve *fcu = static_cast<FCurve *>(list->first); fcu; fcu = fcn) {
106 fcn = fcu->next;
107 BKE_fcurve_free(fcu);
108 }
109
110 /* Clear pointers just in case. */
111 BLI_listbase_clear(list);
112}
113
115
116/* -------------------------------------------------------------------- */
119
121{
122 /* Sanity check. */
123 if (fcu == nullptr) {
124 return nullptr;
125 }
126
127 /* Make a copy. */
128 FCurve *fcu_d = static_cast<FCurve *>(MEM_dupallocN(fcu));
129
130 fcu_d->next = fcu_d->prev = nullptr;
131 fcu_d->grp = nullptr;
132
133 /* Copy curve data. */
134 fcu_d->bezt = static_cast<BezTriple *>(MEM_dupallocN(fcu_d->bezt));
135 fcu_d->fpt = static_cast<FPoint *>(MEM_dupallocN(fcu_d->fpt));
136
137 /* Copy rna-path. */
138 fcu_d->rna_path = static_cast<char *>(MEM_dupallocN(fcu_d->rna_path));
139
140 /* Copy driver. */
141 fcu_d->driver = fcurve_copy_driver(fcu_d->driver);
142
143 /* Copy modifiers. */
144 copy_fmodifiers(&fcu_d->modifiers, &fcu->modifiers);
145
146 /* Return new data. */
147 return fcu_d;
148}
149
151{
152 /* Sanity checks. */
153 if (ELEM(nullptr, dst, src)) {
154 return;
155 }
156
157 /* Clear destination list first. */
159
160 /* Copy one-by-one. */
161 LISTBASE_FOREACH (FCurve *, sfcu, src) {
162 FCurve *dfcu = BKE_fcurve_copy(sfcu);
163 BLI_addtail(dst, dfcu);
164 }
165}
166
168{
170 fcu.rna_path = BLI_strdupn(rna_path.data(), rna_path.size());
171}
172
173void BKE_fmodifier_name_set(FModifier *fcm, const char *name)
174{
175 /* Copy new Modifier name. */
176 STRNCPY(fcm->name, name);
177
178 /* Set default modifier name when name parameter is an empty string.
179 * Ensure the name is unique. */
181 ListBase list = BLI_listbase_from_link((Link *)fcm);
182 BLI_uniquename(&list,
183 fcm,
185 '.',
187 sizeof(fcm->name));
188}
189
191{
192 ChannelDriver *driver = fcu->driver;
193
194 if (driver != nullptr) {
195 LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
196 /* only used targets */
199 }
201 }
202 }
203}
204
205/* ----------------- Finding F-Curves -------------------------- */
206
208 ID *id, void *data, StructRNA *type, const char *prop_name, int index, bool *r_driven)
209{
210 /* Anim vars */
212
213 /* Rna vars */
214 PropertyRNA *prop;
215
216 if (r_driven) {
217 *r_driven = false;
218 }
219
220 /* Only use the current action ??? */
221 if (ELEM(nullptr, adt, adt->action)) {
222 return nullptr;
223 }
224
226 prop = RNA_struct_find_property(&ptr, prop_name);
227 if (prop == nullptr) {
228 return nullptr;
229 }
230
231 const std::optional<std::string> path = RNA_path_from_ID_to_property(&ptr, prop);
232 if (!path) {
233 return nullptr;
234 }
235
236 /* FIXME: The way drivers are handled here (always nullptr-ifying `fcu`) is very weird, this
237 * needs to be re-checked I think?. */
238 bool is_driven = false;
240 adt, path->c_str(), index, nullptr, &is_driven);
241 if (is_driven) {
242 if (r_driven != nullptr) {
243 *r_driven = is_driven;
244 }
245 fcu = nullptr;
246 }
247
248 return fcu;
249}
250
251FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_index)
252{
253 /* Sanity checks. */
254 if (ELEM(nullptr, list, rna_path) || array_index < 0) {
255 return nullptr;
256 }
257
258 /* Check paths of curves, then array indices... */
259 LISTBASE_FOREACH (FCurve *, fcu, list) {
260 /* Check indices first, much cheaper than a string comparison. */
261 /* Simple string-compare (this assumes that they have the same root...) */
262 if (UNLIKELY(fcu->array_index == array_index && fcu->rna_path &&
263 fcu->rna_path[0] == rna_path[0] && STREQ(fcu->rna_path, rna_path)))
264 {
265 return fcu;
266 }
267 }
268
269 return nullptr;
270}
271
273
274/* -------------------------------------------------------------------- */
277
278FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[])
279{
280 /* Sanity checks. */
281 if (ELEM(nullptr, fcu_iter, rna_path)) {
282 return nullptr;
283 }
284
285 /* Check paths of curves, then array indices... */
286 for (FCurve *fcu = fcu_iter; fcu; fcu = fcu->next) {
287 /* Simple string-compare (this assumes that they have the same root...) */
288 if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) {
289 return fcu;
290 }
291 }
292
293 return nullptr;
294}
295
297 AnimData *animdata, const char *rna_path, int rna_index, bAction **r_action, bool *r_driven)
298{
299 if (r_driven != nullptr) {
300 *r_driven = false;
301 }
302 if (r_action != nullptr) {
303 *r_action = nullptr;
304 }
305
307 animdata->action, animdata->slot_handle, {rna_path, rna_index});
308 if (fcurve) {
309 /* Action takes priority over drivers. */
310 if (r_action) {
311 *r_action = animdata->action;
312 }
313 return fcurve;
314 }
315
316 /* If not animated, check if driven. */
317 const bool has_drivers = !BLI_listbase_is_empty(&animdata->drivers);
318 if (has_drivers) {
319 FCurve *fcu = BKE_fcurve_find(&animdata->drivers, rna_path, rna_index);
320
321 if (fcu != nullptr) {
322 if (r_driven != nullptr) {
323 *r_driven = true;
324 }
325 return fcu;
326 }
327 }
328
329 return nullptr;
330}
331
333 PropertyRNA *prop,
334 int rnaindex,
335 AnimData **r_adt,
336 bAction **r_action,
337 bool *r_driven,
338 bool *r_special)
339{
341 nullptr, ptr, prop, rnaindex, r_adt, r_action, r_driven, r_special);
342}
343
345 const PointerRNA *ptr,
346 PropertyRNA *prop,
347 int rnaindex,
348 AnimData **r_animdata,
349 bAction **r_action,
350 bool *r_driven,
351 bool *r_special)
352{
353 if (r_animdata != nullptr) {
354 *r_animdata = nullptr;
355 }
356 if (r_action != nullptr) {
357 *r_action = nullptr;
358 }
359 if (r_driven != nullptr) {
360 *r_driven = false;
361 }
362 if (r_special) {
363 *r_special = false;
364 }
365
366 /* Special case for NLA Control Curves... */
368 NlaStrip *strip = static_cast<NlaStrip *>(ptr->data);
369
370 /* Set the special flag, since it cannot be a normal action/driver
371 * if we've been told to start looking here...
372 */
373 if (r_special) {
374 *r_special = true;
375 }
376 if (r_driven) {
377 *r_driven = false;
378 }
379 if (r_animdata) {
380 *r_animdata = nullptr;
381 }
382 if (r_action) {
383 *r_action = nullptr;
384 }
385
386 /* The F-Curve either exists or it doesn't here... */
387 return BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), rnaindex);
388 }
389
390 /* There must be some RNA-pointer + property combo. */
391 if (!prop || !ptr->owner_id || !RNA_property_animateable(ptr, prop)) {
392 return nullptr;
393 }
394
395 AnimData *adt = BKE_animdata_from_id(ptr->owner_id);
396 if (adt == nullptr) {
397 return nullptr;
398 }
399
400 /* XXX This function call can become a performance bottleneck. */
401 const std::optional<std::string> rna_path = RNA_path_from_ID_to_property(ptr, prop);
402 if (!rna_path) {
403 return nullptr;
404 }
405
406 /* Standard F-Curve from animdata - Animation (Action) or Drivers. */
408 adt, rna_path->c_str(), rnaindex, r_action, r_driven);
409
410 if (fcu != nullptr && r_animdata != nullptr) {
411 *r_animdata = adt;
412 }
413
414 return fcu;
415}
416
418
419/* -------------------------------------------------------------------- */
422
423/* Binary search algorithm for finding where to insert BezTriple,
424 * with optional argument for precision required.
425 * Returns the index to insert at (data already at that index will be offset if replace is 0)
426 */
428 const float frame,
429 const int arraylen,
430 const float threshold,
431 bool *r_replace)
432{
433 int start = 0, end = arraylen;
434 int loopbreaker = 0, maxloop = arraylen * 2;
435
436 /* Initialize replace-flag first. */
437 *r_replace = false;
438
439 /* Sneaky optimizations (don't go through searching process if...):
440 * - Keyframe to be added is to be added out of current bounds.
441 * - Keyframe to be added would replace one of the existing ones on bounds.
442 */
443 if (arraylen <= 0 || array == nullptr) {
444 CLOG_WARN(&LOG, "encountered invalid array");
445 return 0;
446 }
447
448 /* Check whether to add before/after/on. */
449 /* 'First' Keyframe (when only one keyframe, this case is used) */
450 float framenum = array[0].vec[1][0];
451 if (IS_EQT(frame, framenum, threshold)) {
452 *r_replace = true;
453 return 0;
454 }
455 if (frame < framenum) {
456 return 0;
457 }
458
459 /* 'Last' Keyframe */
460 framenum = array[(arraylen - 1)].vec[1][0];
461 if (IS_EQT(frame, framenum, threshold)) {
462 *r_replace = true;
463 return (arraylen - 1);
464 }
465 if (frame > framenum) {
466 return arraylen;
467 }
468
469 /* Most of the time, this loop is just to find where to put it
470 * 'loopbreaker' is just here to prevent infinite loops.
471 */
472 for (loopbreaker = 0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
473 /* Compute and get midpoint. */
474
475 /* We calculate the midpoint this way to avoid int overflows... */
476 const int mid = start + ((end - start) / 2);
477
478 const float midfra = array[mid].vec[1][0];
479
480 /* Check if exactly equal to midpoint. */
481 if (IS_EQT(frame, midfra, threshold)) {
482 *r_replace = true;
483 return mid;
484 }
485
486 /* Repeat in upper/lower half. */
487 if (frame > midfra) {
488 start = mid + 1;
489 }
490 else if (frame < midfra) {
491 end = mid - 1;
492 }
493 }
494
495 /* Print error if loop-limit exceeded. */
496 if (loopbreaker == (maxloop - 1)) {
497 CLOG_ERROR(&LOG, "search taking too long");
498
499 /* Include debug info. */
501 "\tround = %d: start = %d, end = %d, arraylen = %d",
502 loopbreaker,
503 start,
504 end,
505 arraylen);
506 }
507
508 /* Not found, so return where to place it. */
509 return start;
510}
511
513 const float frame,
514 const int arraylen,
515 bool *r_replace)
516{
517 /* This is just a wrapper which uses the default threshold. */
519 array, frame, arraylen, BEZT_BINARYSEARCH_THRESH, r_replace);
520}
521
522/* ...................................... */
523
531static bool get_bounding_bezt_indices(const FCurve *fcu,
532 const bool selected_keys_only,
533 const float frame_range[2],
534 int *r_first,
535 int *r_last)
536{
537 /* Sanity checks. */
538 if (fcu->bezt == nullptr) {
539 return false;
540 }
541
542 *r_first = 0;
543 *r_last = fcu->totvert - 1;
544
545 bool found = false;
546 if (frame_range != nullptr) {
547 /* If a range is passed in find the first and last keyframe within that range. */
548 bool replace = false;
550 fcu->bezt, frame_range[0], fcu->totvert, &replace);
552 fcu->bezt, frame_range[1], fcu->totvert, &replace);
553
554 /* If first and last index are the same, no keyframes were found in the range. */
555 if (*r_first == *r_last) {
556 return false;
557 }
558
559 /* The binary search returns an index where a keyframe would be inserted,
560 * so it needs to be clamped to ensure it is in range of the array. */
561 *r_first = clamp_i(*r_first, 0, fcu->totvert - 1);
562 *r_last = clamp_i(*r_last - 1, 0, fcu->totvert - 1);
563 }
564
565 /* Only include selected items? */
566 if (selected_keys_only) {
567 /* Find first selected. */
568 for (int i = *r_first; i <= *r_last; i++) {
569 BezTriple *bezt = &fcu->bezt[i];
570 if (BEZT_ISSEL_ANY(bezt)) {
571 *r_first = i;
572 found = true;
573 break;
574 }
575 }
576
577 /* Find last selected. */
578 for (int i = *r_last; i >= *r_first; i--) {
579 BezTriple *bezt = &fcu->bezt[i];
580 if (BEZT_ISSEL_ANY(bezt)) {
581 *r_last = i;
582 found = true;
583 break;
584 }
585 }
586 }
587 else {
588 found = true;
589 }
590
591 return found;
592}
593
594static void calculate_bezt_bounds_x(BezTriple *bezt_array,
595 const int index_range[2],
596 const bool include_handles,
597 float *r_min,
598 float *r_max)
599{
600 *r_min = bezt_array[index_range[0]].vec[1][0];
601 *r_max = bezt_array[index_range[1]].vec[1][0];
602
603 if (include_handles) {
604 /* Need to check all handles because they might extend beyond their neighboring keys. */
605 for (int i = index_range[0]; i <= index_range[1]; i++) {
606 const BezTriple *bezt = &bezt_array[i];
607 *r_min = min_fff(*r_min, bezt->vec[0][0], bezt->vec[1][0]);
608 *r_max = max_fff(*r_max, bezt->vec[1][0], bezt->vec[2][0]);
609 }
610 }
611}
612
613static void calculate_bezt_bounds_y(BezTriple *bezt_array,
614 const int index_range[2],
615 const bool selected_keys_only,
616 const bool include_handles,
617 float *r_min,
618 float *r_max)
619{
620 *r_min = bezt_array[index_range[0]].vec[1][1];
621 *r_max = bezt_array[index_range[0]].vec[1][1];
622
623 for (int i = index_range[0]; i <= index_range[1]; i++) {
624 const BezTriple *bezt = &bezt_array[i];
625
626 if (selected_keys_only && !BEZT_ISSEL_ANY(bezt)) {
627 continue;
628 }
629
630 *r_min = min_ff(*r_min, bezt->vec[1][1]);
631 *r_max = max_ff(*r_max, bezt->vec[1][1]);
632
633 if (include_handles) {
634 *r_min = min_fff(*r_min, bezt->vec[0][1], bezt->vec[2][1]);
635 *r_max = max_fff(*r_max, bezt->vec[0][1], bezt->vec[2][1]);
636 }
637 }
638}
639
640static bool calculate_bezt_bounds(const FCurve *fcu,
641 const bool selected_keys_only,
642 const bool include_handles,
643 const float frame_range[2],
644 rctf *r_bounds)
645{
646 int index_range[2];
647 const bool found_indices = get_bounding_bezt_indices(
648 fcu, selected_keys_only, frame_range, &index_range[0], &index_range[1]);
649 if (!found_indices) {
650 return false;
651 }
653 fcu->bezt, index_range, include_handles, &r_bounds->xmin, &r_bounds->xmax);
655 index_range,
656 selected_keys_only,
657 include_handles,
658 &r_bounds->ymin,
659 &r_bounds->ymax);
660 return true;
661}
662
663static bool calculate_fpt_bounds(const FCurve *fcu, const float frame_range[2], rctf *r_bounds)
664{
665 r_bounds->xmin = INFINITY;
666 r_bounds->xmax = -INFINITY;
667 r_bounds->ymin = INFINITY;
668 r_bounds->ymax = -INFINITY;
669
670 const int first_index = 0;
671 const int last_index = fcu->totvert - 1;
672 int start_index = first_index;
673 int end_index = last_index;
674
675 if (frame_range != nullptr) {
676 /* Start index can be calculated because fpt has a key on every full frame. */
677 const float start_index_f = frame_range[0] - fcu->fpt[0].vec[0];
678 const float end_index_f = start_index_f + frame_range[1] - frame_range[0];
679
680 if (start_index_f > fcu->totvert - 1 || end_index_f < 0) {
681 /* Range is outside of keyframe samples. */
682 return false;
683 }
684
685 /* Range might be partially covering keyframe samples. */
686 start_index = clamp_i(start_index_f, 0, fcu->totvert - 1);
687 end_index = clamp_i(end_index_f, 0, fcu->totvert - 1);
688 }
689
690 /* X range can be directly calculated from end verts. */
691 r_bounds->xmin = fcu->fpt[start_index].vec[0];
692 r_bounds->xmax = fcu->fpt[end_index].vec[0];
693
694 for (int i = start_index; i <= end_index; i++) {
695 r_bounds->ymin = min_ff(r_bounds->ymin, fcu->fpt[i].vec[1]);
696 r_bounds->ymax = max_ff(r_bounds->ymax, fcu->fpt[i].vec[1]);
697 }
698
699 return BLI_rctf_is_valid(r_bounds);
700}
701
703 const bool selected_keys_only,
704 const bool include_handles,
705 const float frame_range[2],
706 rctf *r_bounds)
707{
708 if (fcu->totvert == 0) {
709 return false;
710 }
711
712 if (fcu->bezt) {
713 const bool found_bounds = calculate_bezt_bounds(
714 fcu, selected_keys_only, include_handles, frame_range, r_bounds);
715 return found_bounds;
716 }
717
718 if (fcu->fpt) {
719 const bool founds_bounds = calculate_fpt_bounds(fcu, frame_range, r_bounds);
720 return founds_bounds;
721 }
722
723 return false;
724}
725
727 float *r_min,
728 float *r_max,
729 const bool selected_keys_only)
730{
731 float min = 0.0f;
732 float max = 0.0f;
733 bool foundvert = false;
734
735 if (fcu->totvert == 0) {
736 return false;
737 }
738
739 if (fcu->bezt) {
740 int index_range[2];
741 foundvert = get_bounding_bezt_indices(
742 fcu, selected_keys_only, nullptr, &index_range[0], &index_range[1]);
743 if (!foundvert) {
744 return false;
745 }
746 const bool include_handles = false;
747 calculate_bezt_bounds_x(fcu->bezt, index_range, include_handles, &min, &max);
748 }
749 else if (fcu->fpt) {
750 min = fcu->fpt[0].vec[0];
751 max = fcu->fpt[fcu->totvert - 1].vec[0];
752
753 foundvert = true;
754 }
755
756 *r_min = min;
757 *r_max = max;
758
759 return foundvert;
760}
761
763 int fcurve_array_len,
764 const float interval,
765 int *r_frames_len)
766{
767 /* Use `1e-3f` as the smallest possible value since these are converted to integers
768 * and we can be sure `MAXFRAME / 1e-3f < INT_MAX` as it's around half the size. */
769 const double interval_db = max_ff(interval, 1e-3f);
770 GSet *frames_unique = BLI_gset_int_new(__func__);
771 for (int fcurve_index = 0; fcurve_index < fcurve_array_len; fcurve_index++) {
772 const FCurve *fcu = fcurve_array[fcurve_index];
773 for (int i = 0; i < fcu->totvert; i++) {
774 const BezTriple *bezt = &fcu->bezt[i];
775 const double value = round(double(bezt->vec[1][0]) / interval_db);
776 BLI_assert(value > INT_MIN && value < INT_MAX);
777 BLI_gset_add(frames_unique, POINTER_FROM_INT(int(value)));
778 }
779 }
780
781 const size_t frames_len = BLI_gset_len(frames_unique);
782 float *frames = MEM_malloc_arrayN<float>(frames_len, __func__);
783
784 GSetIterator gs_iter;
785 int i = 0;
786 GSET_ITER_INDEX (gs_iter, frames_unique, i) {
787 const int value = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
788 frames[i] = double(value) * interval_db;
789 }
790 BLI_gset_free(frames_unique, nullptr);
791
792 qsort(frames, frames_len, sizeof(*frames), BLI_sortutil_cmp_float);
793 *r_frames_len = frames_len;
794 return frames;
795}
796
798 int fcurve_array_len,
799 int *r_frames_len)
800{
801 return BKE_fcurves_calc_keyed_frames_ex(fcurve_array, fcurve_array_len, 1.0f, r_frames_len);
802}
803
805
806/* -------------------------------------------------------------------- */
809
810void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt)
811{
812 if (active_bezt == nullptr) {
814 return;
815 }
816
817 /* Gracefully handle out-of-bounds pointers. Ideally this would do a BLI_assert() as well, but
818 * then the unit tests would break in debug mode. */
819 const ptrdiff_t offset = active_bezt - fcu->bezt;
820 if (offset < 0 || offset >= fcu->totvert) {
822 return;
823 }
824
825 /* The active keyframe should always be selected. */
826 BLI_assert_msg(BEZT_ISSEL_ANY(active_bezt), "active keyframe must be selected");
827
828 fcu->active_keyframe_index = int(offset);
829}
830
832{
833 const int active_keyframe_index = fcu->active_keyframe_index;
834
835 /* Array access boundary checks. */
836 if (fcu->bezt == nullptr || active_keyframe_index >= fcu->totvert || active_keyframe_index < 0) {
838 }
839
840 const BezTriple *active_bezt = &fcu->bezt[active_keyframe_index];
841 if (((active_bezt->f1 | active_bezt->f2 | active_bezt->f3) & SELECT) == 0) {
842 /* The active keyframe should always be selected. If it's not selected, it can't be active. */
844 }
845
846 return active_keyframe_index;
847}
848
850
851void BKE_fcurve_keyframe_move_time_with_handles(BezTriple *keyframe, const float new_time)
852{
853 const float time_delta = new_time - keyframe->vec[1][0];
854 keyframe->vec[0][0] += time_delta;
855 keyframe->vec[1][0] = new_time;
856 keyframe->vec[2][0] += time_delta;
857}
858
859void BKE_fcurve_keyframe_move_value_with_handles(BezTriple *keyframe, const float new_value)
860{
861 const float value_delta = new_value - keyframe->vec[1][1];
862 keyframe->vec[0][1] += value_delta;
863 keyframe->vec[1][1] = new_value;
864 keyframe->vec[2][1] += value_delta;
865}
866
867/* -------------------------------------------------------------------- */
870
872{
873 /* F-Curve must exist. */
874 if (fcu == nullptr) {
875 return false;
876 }
877
878 /* F-Curve must not have samples - samples are mutually exclusive of keyframes. */
879 if (fcu->fpt) {
880 return false;
881 }
882
883 /* If it has modifiers, none of these should "drastically" alter the curve. */
884 if (fcu->modifiers.first) {
885 /* Check modifiers from last to first, as last will be more influential. */
886 /* TODO: optionally, only check modifier if it is the active one... (Joshua Leung 2010) */
888 /* Ignore if muted/disabled. */
889 if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) {
890 continue;
891 }
892
893 /* Type checks. */
894 switch (fcm->type) {
895 /* Clearly harmless - do nothing. */
899 break;
900
901 /* Sometimes harmful - depending on whether they're "additive" or not. */
903 FMod_Generator *data = (FMod_Generator *)fcm->data;
904
905 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0) {
906 return false;
907 }
908 break;
909 }
912
913 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0) {
914 return false;
915 }
916 break;
917 }
918 /* Always harmful - cannot allow. */
919 default:
920 return false;
921 }
922 }
923 }
924
925 /* Keyframes are usable. */
926 return true;
927}
928
930{
931 return ((fcu->flag & FCURVE_PROTECTED) || (fcu->grp && (fcu->grp->flag & AGRP_PROTECTED)));
932}
933
935{
936 int i;
937 BezTriple *bezt;
938 for (bezt = fcu->bezt, i = 0; i < fcu->totvert; ++i, ++bezt) {
939 if ((bezt->f2 & SELECT) != 0) {
940 return true;
941 }
942 }
943 return false;
944}
945
947{
948 if (!fcu.bezt) {
949 return;
950 }
951 for (int i = 0; i < fcu.totvert; i++) {
952 BEZT_DESEL_ALL(&fcu.bezt[i]);
953 }
954}
955
957{
958 /* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */
959 if (BKE_fcurve_are_keyframes_usable(fcu) == 0) {
960 return false;
961 }
962
963 /* F-Curve must currently be editable too. */
964 if (BKE_fcurve_is_protected(fcu)) {
965 return false;
966 }
967
968 /* F-Curve is keyframable. */
969 return true;
970}
971
973
974/* -------------------------------------------------------------------- */
977
978/* Some utilities for working with FPoints (i.e. 'sampled' animation curve data, such as
979 * data imported from BVH/motion-capture files), which are specialized for use with high density
980 * datasets, which BezTriples/Keyframe data are ill equipped to do. */
981
982float fcurve_samplingcb_evalcurve(FCurve *fcu, void * /*data*/, float evaltime)
983{
984 /* Assume any interference from drivers on the curve is intended... */
985 return evaluate_fcurve(fcu, evaltime);
986}
987
988void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb)
989{
990 /* Sanity checks. */
991 /* TODO: make these tests report errors using reports not CLOG's (Joshua Leung 2009) */
992 if (ELEM(nullptr, fcu, sample_cb)) {
993 CLOG_ERROR(&LOG, "No F-Curve with F-Curve Modifiers to Bake");
994 return;
995 }
996 if (start > end) {
997 CLOG_ERROR(&LOG, "Error: Frame range for Sampled F-Curve creation is inappropriate");
998 return;
999 }
1000
1001 /* Set up sample data. */
1002 FPoint *new_fpt;
1003 FPoint *fpt = new_fpt = MEM_calloc_arrayN<FPoint>(size_t(end) - size_t(start) + 1,
1004 "FPoint Samples");
1005
1006 /* Use the sampling callback at 1-frame intervals from start to end frames. */
1007 for (int cfra = start; cfra <= end; cfra++, fpt++) {
1008 fpt->vec[0] = float(cfra);
1009 fpt->vec[1] = sample_cb(fcu, data, float(cfra));
1010 }
1011
1012 /* Free any existing sample/keyframe data on curve. */
1013 if (fcu->bezt) {
1014 MEM_freeN(fcu->bezt);
1015 }
1016 if (fcu->fpt) {
1017 MEM_freeN(fcu->fpt);
1018 }
1019
1020 /* Store the samples. */
1021 fcu->bezt = nullptr;
1022 fcu->fpt = new_fpt;
1023 fcu->totvert = end - start + 1;
1024}
1025
1027{
1028 bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
1029 /* Baked FCurve points always use linear interpolation. */
1030 bezt->ipo = BEZT_IPO_LIN;
1031 bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
1032}
1033
1034void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end)
1035{
1036
1037 /* Sanity checks. */
1038 /* TODO: make these tests report errors using reports not CLOG's (Joshua Leung 2009). */
1039 if (fcu == nullptr) {
1040 CLOG_ERROR(&LOG, "No F-Curve with F-Curve Modifiers to Un-Bake");
1041 return;
1042 }
1043
1044 if (start > end) {
1045 CLOG_ERROR(&LOG, "Error: Frame range to unbake F-Curve is inappropriate");
1046 return;
1047 }
1048
1049 if (fcu->fpt == nullptr) {
1050 /* No data to unbake. */
1051 CLOG_ERROR(&LOG, "Error: Curve contains no baked keyframes");
1052 return;
1053 }
1054
1055 /* Free any existing sample/keyframe data on the curve. */
1056 if (fcu->bezt) {
1057 MEM_freeN(fcu->bezt);
1058 }
1059
1060 FPoint *fpt = fcu->fpt;
1061 int keyframes_to_insert = end - start;
1062 int sample_points = fcu->totvert;
1063
1064 BezTriple *bezt = fcu->bezt = MEM_calloc_arrayN<BezTriple>(keyframes_to_insert, __func__);
1065 fcu->totvert = keyframes_to_insert;
1066
1067 /* Get first sample point to 'copy' as keyframe. */
1068 for (; sample_points && (fpt->vec[0] < start); fpt++, sample_points--) {
1069 /* pass */
1070 }
1071
1072 /* Current position in the timeline. */
1073 int cur_pos = start;
1074
1075 /* Add leading dummy flat points if needed. */
1076 for (; keyframes_to_insert && (fpt->vec[0] > start); cur_pos++, bezt++, keyframes_to_insert--) {
1078 bezt->vec[1][0] = float(cur_pos);
1079 bezt->vec[1][1] = fpt->vec[1];
1080 }
1081
1082 /* Copy actual sample points. */
1083 for (; keyframes_to_insert && sample_points;
1084 cur_pos++, bezt++, keyframes_to_insert--, fpt++, sample_points--)
1085 {
1087 copy_v2_v2(bezt->vec[1], fpt->vec);
1088 }
1089
1090 /* Add trailing dummy flat points if needed. */
1091 for (fpt--; keyframes_to_insert; cur_pos++, bezt++, keyframes_to_insert--) {
1093 bezt->vec[1][0] = float(cur_pos);
1094 bezt->vec[1][1] = fpt->vec[1];
1095 }
1096
1097 MEM_SAFE_FREE(fcu->fpt);
1098
1099 /* Not strictly needed since we use linear interpolation, but better be consistent here. */
1101}
1102
1103/* ***************************** F-Curve Sanity ********************************* */
1104/* The functions here are used in various parts of Blender, usually after some editing
1105 * of keyframe data has occurred. They ensure that keyframe data is properly ordered and
1106 * that the handles are correct.
1107 */
1108
1110{
1111 FModifier *fcm = static_cast<FModifier *>(fcu->modifiers.first);
1112
1113 if (!fcm || fcm->type != FMODIFIER_TYPE_CYCLES) {
1114 return FCU_CYCLE_NONE;
1115 }
1116
1118 return FCU_CYCLE_NONE;
1119 }
1120
1122 return FCU_CYCLE_NONE;
1123 }
1124
1125 FMod_Cycles *data = (FMod_Cycles *)fcm->data;
1126
1127 if (data && data->after_cycles == 0 && data->before_cycles == 0) {
1128 if (data->before_mode == FCM_EXTRAPOLATE_CYCLIC && data->after_mode == FCM_EXTRAPOLATE_CYCLIC)
1129 {
1130 return FCU_CYCLE_PERFECT;
1131 }
1132
1135 {
1136 return FCU_CYCLE_OFFSET;
1137 }
1138 }
1139
1140 return FCU_CYCLE_NONE;
1141}
1142
1144{
1146}
1147
1148/* Shifts 'in' by the difference in coordinates between 'to' and 'from',
1149 * using 'out' as the output buffer.
1150 * When 'to' and 'from' are end points of the loop, this moves the 'in' point one loop cycle.
1151 */
1153 bool cycle, BezTriple *out, const BezTriple *in, const BezTriple *from, const BezTriple *to)
1154{
1155 if (!cycle) {
1156 return nullptr;
1157 }
1158
1159 memcpy(out, in, sizeof(BezTriple));
1160
1161 float delta[3];
1162 sub_v3_v3v3(delta, to->vec[1], from->vec[1]);
1163
1164 for (int i = 0; i < 3; i++) {
1165 add_v3_v3(out->vec[i], delta);
1166 }
1167
1168 return out;
1169}
1170
1172{
1173 using namespace blender;
1174 /* Error checking:
1175 * - Need at least two points.
1176 * - Need bezier keys.
1177 * - Only bezier-interpolation has handles (for now).
1178 */
1179 if (ELEM(nullptr, fcu, fcu->bezt) ||
1180 (fcu->totvert < 2) /*|| ELEM(fcu->ipo, BEZT_IPO_CONST, BEZT_IPO_LIN) */)
1181 {
1182 return;
1183 }
1184
1185 /* If the first modifier is Cycles, smooth the curve through the cycle. */
1186 BezTriple *first = &fcu->bezt[0];
1187 BezTriple *last = &fcu->bezt[fcu->totvert - 1];
1188 const bool cycle = BKE_fcurve_is_cyclic(fcu) && BEZT_IS_AUTOH(first) && BEZT_IS_AUTOH(last);
1189
1190 threading::parallel_for(IndexRange(fcu->totvert), 256, [&](const IndexRange range) {
1191 BezTriple tmp;
1192 for (const int i : range) {
1193 BezTriple *bezt = &fcu->bezt[i];
1194 BezTriple *prev = nullptr;
1195 BezTriple *next = nullptr;
1196 if (i > 0) {
1197 prev = (bezt - 1);
1198 }
1199 else {
1200 prev = cycle_offset_triple(cycle, &tmp, &fcu->bezt[fcu->totvert - 2], last, first);
1201 }
1202 if (i < fcu->totvert - 1) {
1203 next = (bezt + 1);
1204 }
1205 else {
1206 next = cycle_offset_triple(cycle, &tmp, &fcu->bezt[1], first, last);
1207 }
1208
1209 /* Clamp timing of handles to be on either side of beztriple. The threshold with
1210 * increment/decrement ulp ensures that the handle length doesn't reach 0 at which point
1211 * there would be no way to ensure that handles stay aligned. This adds an issue where if a
1212 * handle is scaled to 0, the other side is set to be horizontal.
1213 * See #141029 for more info. */
1214 const float threshold = 0.001;
1215 CLAMP_MAX(bezt->vec[0][0], decrement_ulp(bezt->vec[1][0] - threshold));
1216 CLAMP_MIN(bezt->vec[2][0], increment_ulp(bezt->vec[1][0] + threshold));
1217
1218 /* Calculate auto-handles. */
1219 BKE_nurb_handle_calc_ex(bezt, prev, next, handle_sel_flag, true, fcu->auto_smoothing);
1220
1221 /* For automatic ease in and out. */
1222 if (BEZT_IS_AUTOH(bezt) && !cycle) {
1223 /* Only do this on first or last beztriple. */
1224 if (ELEM(i, 0, fcu->totvert - 1)) {
1225 /* Set both handles to have same horizontal value as keyframe. */
1226 if (fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT) {
1227 bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1];
1228 /* Remember that these keyframes are special, they don't need to be adjusted. */
1229 bezt->auto_handle_type = HD_AUTOTYPE_LOCKED_FINAL;
1230 }
1231 }
1232 }
1233
1234 /* Avoid total smoothing failure on duplicate keyframes (can happen during grab). */
1235 if (prev && prev->vec[1][0] >= bezt->vec[1][0]) {
1236 prev->auto_handle_type = bezt->auto_handle_type = HD_AUTOTYPE_LOCKED_FINAL;
1237 }
1238 }
1239 });
1240
1241 /* If cyclic extrapolation and Auto Clamp has triggered, ensure it is symmetric. */
1242 if (cycle && (first->auto_handle_type != HD_AUTOTYPE_NORMAL ||
1243 last->auto_handle_type != HD_AUTOTYPE_NORMAL))
1244 {
1245 first->vec[0][1] = first->vec[2][1] = first->vec[1][1];
1246 last->vec[0][1] = last->vec[2][1] = last->vec[1][1];
1247 first->auto_handle_type = last->auto_handle_type = HD_AUTOTYPE_LOCKED_FINAL;
1248 }
1249
1250 /* Do a second pass for auto handle: compute the handle to have 0 acceleration step. */
1251 if (fcu->auto_smoothing != FCURVE_SMOOTH_NONE) {
1252 BKE_nurb_handle_smooth_fcurve(fcu->bezt, fcu->totvert, cycle);
1253 }
1254}
1255
1260
1261void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_handle)
1262{
1263 /* Only beztriples have handles (bpoints don't though). */
1264 if (ELEM(nullptr, fcu, fcu->bezt)) {
1265 return;
1266 }
1267
1268 /* Loop over beztriples. */
1269 BezTriple *bezt;
1270 uint a;
1271 for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) {
1273 bezt, sel_flag, use_handle ? NURB_HANDLE_TEST_EACH : NURB_HANDLE_TEST_KNOT_ONLY, false);
1274 }
1275
1276 /* Recalculate handles. */
1277 BKE_fcurve_handles_recalc_ex(fcu, sel_flag);
1278}
1279
1281{
1282 if (fcu->bezt == nullptr) {
1283 return;
1284 }
1285
1286 /* Keep adjusting order of beztriples until nothing moves (bubble-sort). */
1287 BezTriple *bezt;
1288 uint a;
1289
1290 bool ok = true;
1291 while (ok) {
1292 ok = false;
1293 /* Currently, will only be needed when there are beztriples. */
1294
1295 /* Loop over ALL points to adjust position in array and recalculate handles. */
1296 for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) {
1297 /* Check if there's a next beztriple which we could try to swap with current. */
1298 if (a < (fcu->totvert - 1)) {
1299 /* Swap if one is after the other (and indicate that order has changed). */
1300 if (bezt->vec[1][0] > (bezt + 1)->vec[1][0]) {
1301 std::swap(*bezt, *(bezt + 1));
1302 ok = true;
1303 }
1304 }
1305 }
1306 }
1307
1308 for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) {
1309 /* If either one of both of the points exceeds crosses over the keyframe time... */
1310 if ((bezt->vec[0][0] > bezt->vec[1][0]) && (bezt->vec[2][0] < bezt->vec[1][0])) {
1311 /* Swap handles if they have switched sides for some reason. */
1312 swap_v2_v2(bezt->vec[0], bezt->vec[2]);
1313 }
1314 else {
1315 /* Clamp handles. */
1316 CLAMP_MAX(bezt->vec[0][0], bezt->vec[1][0]);
1317 CLAMP_MIN(bezt->vec[2][0], bezt->vec[1][0]);
1318 }
1319 }
1320}
1321
1323{
1324 uint a;
1325
1326 /* Sanity checks. */
1327 if (fcu == nullptr) {
1328 return false;
1329 }
1330
1331 /* Currently, only need to test beztriples. */
1332 if (fcu->bezt) {
1333 BezTriple *bezt;
1334
1335 /* Loop through all BezTriples, stopping when one exceeds the one after it. */
1336 for (a = 0, bezt = fcu->bezt; a < (fcu->totvert - 1); a++, bezt++) {
1337 if (bezt->vec[1][0] > (bezt + 1)->vec[1][0]) {
1338 return true;
1339 }
1340 }
1341 }
1342 else if (fcu->fpt) {
1343 FPoint *fpt;
1344
1345 /* Loop through all FPoints, stopping when one exceeds the one after it. */
1346 for (a = 0, fpt = fcu->fpt; a < (fcu->totvert - 1); a++, fpt++) {
1347 if (fpt->vec[0] > (fpt + 1)->vec[0]) {
1348 return true;
1349 }
1350 }
1351 }
1352
1353 /* None need any swapping. */
1354 return false;
1355}
1356
1358
1359/* -------------------------------------------------------------------- */
1362
1363void BKE_fcurve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
1364{
1365 float h1[2], h2[2], len1, len2, len, fac;
1366
1367 /* Calculate handle deltas. */
1368 h1[0] = v1[0] - v2[0];
1369 h1[1] = v1[1] - v2[1];
1370
1371 h2[0] = v4[0] - v3[0];
1372 h2[1] = v4[1] - v3[1];
1373
1374 /* Calculate distances:
1375 * - len = Span of time between keyframes.
1376 * - len1 = Length of handle of start key.
1377 * - len2 = Length of handle of end key.
1378 */
1379 len = v4[0] - v1[0];
1380 len1 = fabsf(h1[0]);
1381 len2 = fabsf(h2[0]);
1382
1383 /* If the handles have no length, no need to do any corrections. */
1384 if ((len1 + len2) == 0.0f) {
1385 return;
1386 }
1387
1388 /* To prevent looping or rewinding, handles cannot
1389 * exceed the adjacent key-frames time position. */
1390 if (len1 > len) {
1391 fac = len / len1;
1392 v2[0] = (v1[0] - fac * h1[0]);
1393 v2[1] = (v1[1] - fac * h1[1]);
1394 }
1395
1396 if (len2 > len) {
1397 fac = len / len2;
1398 v3[0] = (v4[0] - fac * h2[0]);
1399 v3[1] = (v4[1] - fac * h2[1]);
1400 }
1401}
1402
1409static int solve_cubic(double c0, double c1, double c2, double c3, float *o)
1410{
1411 double a, b, c, p, q, d, t, phi;
1412 int nr = 0;
1413
1414 if (c3 != 0.0) {
1415 a = c2 / c3;
1416 b = c1 / c3;
1417 c = c0 / c3;
1418 a = a / 3;
1419
1420 p = b / 3 - a * a;
1421 q = (2 * a * a * a - a * b + c) / 2;
1422 d = q * q + p * p * p;
1423
1424 if (d > 0.0) {
1425 t = sqrt(d);
1426 o[0] = float(sqrt3d(-q + t) + sqrt3d(-q - t) - a);
1427
1428 if ((o[0] >= float(SMALL)) && (o[0] <= 1.000001f)) {
1429 return 1;
1430 }
1431 return 0;
1432 }
1433
1434 if (d == 0.0) {
1435 t = sqrt3d(-q);
1436 o[0] = float(2 * t - a);
1437
1438 if ((o[0] >= float(SMALL)) && (o[0] <= 1.000001f)) {
1439 nr++;
1440 }
1441 o[nr] = float(-t - a);
1442
1443 if ((o[nr] >= float(SMALL)) && (o[nr] <= 1.000001f)) {
1444 return nr + 1;
1445 }
1446 return nr;
1447 }
1448
1449 phi = acos(-q / sqrt(-(p * p * p)));
1450 t = sqrt(-p);
1451 p = cos(phi / 3);
1452 q = sqrt(3 - 3 * p * p);
1453 o[0] = float(2 * t * p - a);
1454
1455 if ((o[0] >= float(SMALL)) && (o[0] <= 1.000001f)) {
1456 nr++;
1457 }
1458 o[nr] = float(-t * (p + q) - a);
1459
1460 if ((o[nr] >= float(SMALL)) && (o[nr] <= 1.000001f)) {
1461 nr++;
1462 }
1463 o[nr] = float(-t * (p - q) - a);
1464
1465 if ((o[nr] >= float(SMALL)) && (o[nr] <= 1.000001f)) {
1466 return nr + 1;
1467 }
1468 return nr;
1469 }
1470 a = c2;
1471 b = c1;
1472 c = c0;
1473
1474 if (a != 0.0) {
1475 /* Discriminant */
1476 p = b * b - 4 * a * c;
1477
1478 if (p > 0) {
1479 p = sqrt(p);
1480 o[0] = float((-b - p) / (2 * a));
1481
1482 if ((o[0] >= float(SMALL)) && (o[0] <= 1.000001f)) {
1483 nr++;
1484 }
1485 o[nr] = float((-b + p) / (2 * a));
1486
1487 if ((o[nr] >= float(SMALL)) && (o[nr] <= 1.000001f)) {
1488 return nr + 1;
1489 }
1490 return nr;
1491 }
1492
1493 if (p == 0) {
1494 o[0] = float(-b / (2 * a));
1495 if ((o[0] >= float(SMALL)) && (o[0] <= 1.000001f)) {
1496 return 1;
1497 }
1498 }
1499
1500 return 0;
1501 }
1502
1503 if (b != 0.0) {
1504 o[0] = float(-c / b);
1505
1506 if ((o[0] >= float(SMALL)) && (o[0] <= 1.000001f)) {
1507 return 1;
1508 }
1509 return 0;
1510 }
1511
1512 if (c == 0.0) {
1513 o[0] = 0.0;
1514 return 1;
1515 }
1516
1517 return 0;
1518}
1519
1520/* Find root(s) ('zero') of a Bezier curve. */
1521static int findzero(float x, float q0, float q1, float q2, float q3, float *o)
1522{
1523 const double c0 = q0 - x;
1524 const double c1 = 3.0f * (q1 - q0);
1525 const double c2 = 3.0f * (q0 - 2.0f * q1 + q2);
1526 const double c3 = q3 - q0 + 3.0f * (q1 - q2);
1527
1528 return solve_cubic(c0, c1, c2, c3, o);
1529}
1530
1531static void berekeny(float f1, float f2, float f3, float f4, float *o, int b)
1532{
1533 float t, c0, c1, c2, c3;
1534 int a;
1535
1536 c0 = f1;
1537 c1 = 3.0f * (f2 - f1);
1538 c2 = 3.0f * (f1 - 2.0f * f2 + f3);
1539 c3 = f4 - f1 + 3.0f * (f2 - f3);
1540
1541 for (a = 0; a < b; a++) {
1542 t = o[a];
1543 o[a] = c0 + t * c1 + t * t * c2 + t * t * t * c3;
1544 }
1545}
1546
1547static void fcurve_bezt_free(FCurve *fcu)
1548{
1549 MEM_SAFE_FREE(fcu->bezt);
1550 fcu->totvert = 0;
1551}
1552
1554 BezTriple *prev,
1555 BezTriple *next,
1556 float *r_pdelta)
1557{
1558 /* The four points that make up this section of the Bezier curve. */
1559 const float *prev_coords = prev->vec[1];
1560 float *prev_handle_right = prev->vec[2];
1561 float *next_handle_left = next->vec[0];
1562 const float *next_coords = next->vec[1];
1563
1564 float *new_handle_left = bezt->vec[0];
1565 const float *new_coords = bezt->vec[1];
1566 float *new_handle_right = bezt->vec[2];
1567
1568 if (new_coords[0] <= prev_coords[0] || new_coords[0] >= next_coords[0]) {
1569 /* The new keyframe is outside the (prev_coords, next_coords) range. */
1570 return false;
1571 }
1572
1573 /* Apply evaluation-time limits and compute the effective curve. */
1574 BKE_fcurve_correct_bezpart(prev_coords, prev_handle_right, next_handle_left, next_coords);
1575 float roots[4];
1576 if (!findzero(new_coords[0],
1577 prev_coords[0],
1578 prev_handle_right[0],
1579 next_handle_left[0],
1580 next_coords[0],
1581 roots))
1582 {
1583 return false;
1584 }
1585
1586 const float t = roots[0]; /* Percentage of the curve at which the split should occur. */
1587 if (t <= 0.0f || t >= 1.0f) {
1588 /* The split would occur outside the curve, which isn't possible. */
1589 return false;
1590 }
1591
1592 /* De Casteljau split, requires three iterations of splitting.
1593 * See https://pomax.github.io/bezierinfo/#decasteljau */
1594 float split1[3][2], split2[2][2], split3[2];
1595 interp_v2_v2v2(split1[0], prev_coords, prev_handle_right, t);
1596 interp_v2_v2v2(split1[1], prev_handle_right, next_handle_left, t);
1597 interp_v2_v2v2(split1[2], next_handle_left, next_coords, t);
1598 interp_v2_v2v2(split2[0], split1[0], split1[1], t);
1599 interp_v2_v2v2(split2[1], split1[1], split1[2], t);
1600 interp_v2_v2v2(split3, split2[0], split2[1], t);
1601
1602 /* Update the existing handles. */
1603 copy_v2_v2(prev_handle_right, split1[0]);
1604 copy_v2_v2(next_handle_left, split1[2]);
1605
1606 float diff_coords[2];
1607 sub_v2_v2v2(diff_coords, new_coords, split3);
1608 add_v2_v2v2(new_handle_left, split2[0], diff_coords);
1609 add_v2_v2v2(new_handle_right, split2[1], diff_coords);
1610
1611 *r_pdelta = diff_coords[1];
1612 return true;
1613}
1614
1615void BKE_fcurve_bezt_resize(FCurve *fcu, const int new_totvert)
1616{
1617 BLI_assert(new_totvert >= 0);
1618
1619 /* No early return when new_totvert == fcu->totvert. There is no way to know the intention of the
1620 * caller, nor the history of the FCurve so far, so `fcu->bezt` may actually have allocated space
1621 * for more than `fcu->totvert` keys. */
1622
1623 if (new_totvert == 0) {
1624 fcurve_bezt_free(fcu);
1625 return;
1626 }
1627
1628 fcu->bezt = static_cast<BezTriple *>(
1629 MEM_reallocN(fcu->bezt, new_totvert * sizeof(*(fcu->bezt))));
1630
1631 /* Zero out all the newly-allocated beztriples. This is necessary, as it is likely that only some
1632 * of the fields will actually be updated by the caller. */
1633 const int old_totvert = fcu->totvert;
1634 if (new_totvert > old_totvert) {
1635 memset(&fcu->bezt[old_totvert], 0, sizeof(fcu->bezt[0]) * (new_totvert - old_totvert));
1636 }
1637
1638 fcu->totvert = new_totvert;
1639}
1640
1641void BKE_fcurve_delete_key(FCurve *fcu, int index)
1642{
1643 /* sanity check */
1644 if (fcu == nullptr) {
1645 return;
1646 }
1647
1648 /* verify the index:
1649 * 1) cannot be greater than the number of available keyframes
1650 * 2) negative indices are for specifying a value from the end of the array
1651 */
1652 if (abs(index) >= fcu->totvert) {
1653 return;
1654 }
1655 if (index < 0) {
1656 index += fcu->totvert;
1657 }
1658
1659 /* Delete this keyframe */
1660 memmove(
1661 &fcu->bezt[index], &fcu->bezt[index + 1], sizeof(BezTriple) * (fcu->totvert - index - 1));
1662 fcu->totvert--;
1663
1664 /* Free the array of BezTriples if there are not keyframes */
1665 if (fcu->totvert == 0) {
1666 fcurve_bezt_free(fcu);
1667 }
1668}
1669
1671{
1672 BLI_assert(fcu != nullptr);
1673 BLI_assert(fcu->bezt != nullptr);
1674 BLI_assert(index_range[1] > index_range[0]);
1675 BLI_assert(index_range[1] <= fcu->totvert);
1676
1677 const int removed_index_count = index_range[1] - index_range[0];
1678 memmove(&fcu->bezt[index_range[0]],
1679 &fcu->bezt[index_range[1]],
1680 sizeof(BezTriple) * (fcu->totvert - index_range[1]));
1681 fcu->totvert -= removed_index_count;
1682
1683 if (fcu->totvert == 0) {
1684 fcurve_bezt_free(fcu);
1685 }
1686}
1687
1689 const BezTriple *a, const int size_a, const BezTriple *b, const int size_b, int *r_merged_size)
1690{
1691 BezTriple *large_array = MEM_calloc_arrayN<BezTriple>(size_t(size_a + size_b), "beztriple");
1692
1693 int iterator_a = 0;
1694 int iterator_b = 0;
1695 *r_merged_size = 0;
1696
1697 /* For comparing if keyframes are at the same x-value. */
1698 const int max_ulps = 32;
1699
1700 while (iterator_a < size_a || iterator_b < size_b) {
1701 if (iterator_a >= size_a) {
1702 const int remaining_keys = size_b - iterator_b;
1703 memcpy(&large_array[*r_merged_size], &b[iterator_b], sizeof(BezTriple) * remaining_keys);
1704 (*r_merged_size) += remaining_keys;
1705 break;
1706 }
1707 if (iterator_b >= size_b) {
1708 const int remaining_keys = size_a - iterator_a;
1709 memcpy(&large_array[*r_merged_size], &a[iterator_a], sizeof(BezTriple) * remaining_keys);
1710 (*r_merged_size) += remaining_keys;
1711 break;
1712 }
1713
1715 a[iterator_a].vec[1][0], b[iterator_b].vec[1][0], BEZT_BINARYSEARCH_THRESH, max_ulps))
1716 {
1717 memcpy(&large_array[*r_merged_size], &a[iterator_a], sizeof(BezTriple));
1718 iterator_a++;
1719 iterator_b++;
1720 }
1721 else if (a[iterator_a].vec[1][0] < b[iterator_b].vec[1][0]) {
1722 memcpy(&large_array[*r_merged_size], &a[iterator_a], sizeof(BezTriple));
1723 iterator_a++;
1724 }
1725 else {
1726 memcpy(&large_array[*r_merged_size], &b[iterator_b], sizeof(BezTriple));
1727 iterator_b++;
1728 }
1729 (*r_merged_size)++;
1730 }
1731
1732 BezTriple *minimal_array;
1733 if (*r_merged_size < size_a + size_b) {
1734 minimal_array = static_cast<BezTriple *>(
1735 MEM_reallocN(large_array, sizeof(BezTriple) * (*r_merged_size)));
1736 }
1737 else {
1738 minimal_array = large_array;
1739 }
1740
1741 return minimal_array;
1742}
1743
1745{
1746 if (fcu->bezt == nullptr) { /* ignore baked curves */
1747 return false;
1748 }
1749
1750 bool changed = false;
1751
1752 /* Delete selected BezTriples */
1753 for (int i = 0; i < fcu->totvert; i++) {
1754 if (fcu->bezt[i].f2 & SELECT) {
1755 if (i == fcu->active_keyframe_index) {
1756 BKE_fcurve_active_keyframe_set(fcu, nullptr);
1757 }
1758 memmove(&fcu->bezt[i], &fcu->bezt[i + 1], sizeof(BezTriple) * (fcu->totvert - i - 1));
1759 fcu->totvert--;
1760 i--;
1761 changed = true;
1762 }
1763 }
1764
1765 /* Free the array of BezTriples if there are not keyframes */
1766 if (fcu->totvert == 0) {
1767 fcurve_bezt_free(fcu);
1768 }
1769
1770 return changed;
1771}
1772
1774{
1775 fcurve_bezt_free(fcu);
1776}
1777
1778/* Time + Average value */
1781 float frame; /* frame to cluster around */
1782 float val; /* average value */
1783
1784 size_t tot_count; /* number of keyframes that have been averaged */
1785 size_t del_count; /* number of keyframes of this sort that have been deleted so far */
1786};
1787
1788void BKE_fcurve_merge_duplicate_keys(FCurve *fcu, const int sel_flag, const bool use_handle)
1789{
1790 /* NOTE: We assume that all keys are sorted */
1791 ListBase retained_keys = {nullptr, nullptr};
1792 const bool can_average_points = ((fcu->flag & (FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES)) ==
1793 0);
1794
1795 /* sanity checks */
1796 if ((fcu->totvert == 0) || (fcu->bezt == nullptr)) {
1797 return;
1798 }
1799
1800 /* 1) Identify selected keyframes, and average the values on those
1801 * in case there are collisions due to multiple keys getting scaled
1802 * to all end up on the same frame
1803 */
1804 for (int i = 0; i < fcu->totvert; i++) {
1805 BezTriple *bezt = &fcu->bezt[i];
1806
1807 if (BEZT_ISSEL_ANY(bezt)) {
1808 bool found = false;
1809
1810 /* If there's another selected frame here, merge it */
1811 LISTBASE_FOREACH_BACKWARD (tRetainedKeyframe *, rk, &retained_keys) {
1812 if (IS_EQT(rk->frame, bezt->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
1813 rk->val += bezt->vec[1][1];
1814 rk->tot_count++;
1815
1816 found = true;
1817 break;
1818 }
1819 if (rk->frame < bezt->vec[1][0]) {
1820 /* Terminate early if have passed the supposed insertion point? */
1821 break;
1822 }
1823 }
1824
1825 /* If nothing found yet, create a new one */
1826 if (found == false) {
1827 tRetainedKeyframe *rk = MEM_callocN<tRetainedKeyframe>("tRetainedKeyframe");
1828
1829 rk->frame = bezt->vec[1][0];
1830 rk->val = bezt->vec[1][1];
1831 rk->tot_count = 1;
1832
1833 BLI_addtail(&retained_keys, rk);
1834 }
1835 }
1836 }
1837
1838 if (BLI_listbase_is_empty(&retained_keys)) {
1839 /* This may happen if none of the points were selected... */
1840 if (G.debug & G_DEBUG) {
1841 printf("%s: nothing to do for FCurve %p (rna_path = '%s')\n", __func__, fcu, fcu->rna_path);
1842 }
1843 return;
1844 }
1845
1846 /* Compute the average values for each retained keyframe */
1847 LISTBASE_FOREACH (tRetainedKeyframe *, rk, &retained_keys) {
1848 rk->val = rk->val / float(rk->tot_count);
1849 }
1850
1851 /* 2) Delete all keyframes duplicating the "retained keys" found above
1852 * - Most of these will be unselected keyframes
1853 * - Some will be selected keyframes though. For those, we only keep the last one
1854 * (or else everything is gone), and replace its value with the averaged value.
1855 */
1856 for (int i = fcu->totvert - 1; i >= 0; i--) {
1857 BezTriple *bezt = &fcu->bezt[i];
1858
1859 /* Is this keyframe a candidate for deletion? */
1860 /* TODO: Replace loop with an O(1) lookup instead */
1861 LISTBASE_FOREACH_BACKWARD (tRetainedKeyframe *, rk, &retained_keys) {
1862 if (IS_EQT(bezt->vec[1][0], rk->frame, BEZT_BINARYSEARCH_THRESH)) {
1863 /* Selected keys are treated with greater care than unselected ones... */
1864 if (BEZT_ISSEL_ANY(bezt)) {
1865 /* - If this is the last selected key left (based on rk->del_count) ==> UPDATE IT
1866 * (or else we wouldn't have any keyframe left here)
1867 * - Otherwise, there are still other selected keyframes on this frame
1868 * to be merged down still ==> DELETE IT
1869 */
1870 if (rk->del_count == rk->tot_count - 1) {
1871 /* Update keyframe... */
1872 if (can_average_points) {
1873 /* TODO: update handles too? */
1874 bezt->vec[1][1] = rk->val;
1875 }
1876 }
1877 else {
1878 /* Delete Keyframe */
1880 }
1881
1882 /* Update count of how many we've deleted
1883 * - It should only matter that we're doing this for all but the last one
1884 */
1885 rk->del_count++;
1886 }
1887 else {
1888 /* Always delete - Unselected keys don't matter */
1890 }
1891
1892 /* Stop the RK search... we've found our match now */
1893 break;
1894 }
1895 }
1896 }
1897
1898 /* 3) Recalculate handles */
1899 testhandles_fcurve(fcu, eBezTriple_Flag(sel_flag), use_handle);
1900
1901 /* cleanup */
1902 BLI_freelistN(&retained_keys);
1903}
1904
1906{
1907 if (fcu->totvert < 2) {
1908 return;
1909 }
1910
1911 BLI_assert_msg(fcu->bezt, "this function only works with regular (non-sampled) FCurves");
1912 if (fcu->bezt == nullptr) {
1913 return;
1914 }
1915
1916 int prev_bezt_index = 0;
1917 for (int i = 1; i < fcu->totvert; i++) {
1918 BezTriple *bezt = &fcu->bezt[i];
1919 BezTriple *prev_bezt = &fcu->bezt[prev_bezt_index];
1920
1921 const float bezt_x = bezt->vec[1][0];
1922 const float prev_x = prev_bezt->vec[1][0];
1923
1924 if (bezt_x - prev_x <= BEZT_BINARYSEARCH_THRESH) {
1925 /* Replace 'prev_bezt', as it has the same X-coord as 'bezt' and the last one wins. */
1926 *prev_bezt = *bezt;
1927
1928 if (floor(bezt_x) == bezt_x) {
1929 /* Keep the 'bezt_x' coordinate, as being on a frame is more desirable
1930 * than being ever so slightly off. */
1931 }
1932 else {
1933 /* Move the retained key to the old X-coordinate, to 'anchor' the X-coordinate used for
1934 * subsequent comparisons. Without this, the reference X-coordinate would keep moving
1935 * forward in time, potentially merging in more keys than desired. */
1937 }
1938 continue;
1939 }
1940
1941 /* Next iteration should look at the current element. However, because of the deletions, that
1942 * may not be at index 'i'; after this increment, `prev_bezt_index` points at where the current
1943 * element should go. */
1944 prev_bezt_index++;
1945
1946 if (prev_bezt_index != i) {
1947 /* This bezt should be kept, so copy it to its new location in the array. */
1948 fcu->bezt[prev_bezt_index] = *bezt;
1949 }
1950 }
1951
1952 BKE_fcurve_bezt_resize(fcu, prev_bezt_index + 1);
1953}
1954
1956
1957/* -------------------------------------------------------------------- */
1960
1962 const BezTriple *bezts,
1963 float evaltime,
1964 int endpoint_offset,
1965 int direction_to_neighbor)
1966{
1967 /* The first/last keyframe. */
1968 const BezTriple *endpoint_bezt = bezts + endpoint_offset;
1969 /* The second (to last) keyframe. */
1970 const BezTriple *neighbor_bezt = endpoint_bezt + direction_to_neighbor;
1971
1972 if (endpoint_bezt->ipo == BEZT_IPO_CONST || fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT ||
1973 (fcu->flag & FCURVE_DISCRETE_VALUES) != 0)
1974 {
1975 /* Constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, so just extend the
1976 * endpoint's value. */
1977 return endpoint_bezt->vec[1][1];
1978 }
1979
1980 if (endpoint_bezt->ipo == BEZT_IPO_LIN) {
1981 /* Use the next center point instead of our own handle for linear interpolated extrapolate. */
1982 if (fcu->totvert == 1) {
1983 return endpoint_bezt->vec[1][1];
1984 }
1985
1986 const float dx = endpoint_bezt->vec[1][0] - evaltime;
1987 float fac = neighbor_bezt->vec[1][0] - endpoint_bezt->vec[1][0];
1988
1989 /* Prevent division by zero. */
1990 if (fac == 0.0f) {
1991 return endpoint_bezt->vec[1][1];
1992 }
1993
1994 fac = (neighbor_bezt->vec[1][1] - endpoint_bezt->vec[1][1]) / fac;
1995 return endpoint_bezt->vec[1][1] - (fac * dx);
1996 }
1997
1998 /* Use the gradient of the second handle (later) of neighbor to calculate the gradient and thus
1999 * the value of the curve at evaluation time. */
2000 const int handle = direction_to_neighbor > 0 ? 0 : 2;
2001 const float dx = endpoint_bezt->vec[1][0] - evaltime;
2002 float fac = endpoint_bezt->vec[1][0] - endpoint_bezt->vec[handle][0];
2003
2004 /* Prevent division by zero. */
2005 if (fac == 0.0f) {
2006 return endpoint_bezt->vec[1][1];
2007 }
2008
2009 fac = (endpoint_bezt->vec[1][1] - endpoint_bezt->vec[handle][1]) / fac;
2010 return endpoint_bezt->vec[1][1] - (fac * dx);
2011}
2012
2014 const BezTriple *bezts,
2015 float evaltime)
2016{
2017 const float eps = 1.e-8f;
2018 uint a;
2019
2020 /* Evaluation-time occurs somewhere in the middle of the curve. */
2021 bool exact = false;
2022
2023 /* Use binary search to find appropriate keyframes...
2024 *
2025 * The threshold here has the following constraints:
2026 * - 0.001 is too coarse:
2027 * We get artifacts with 2cm driver movements at 1BU = 1m (see #40332).
2028 *
2029 * - 0.00001 is too fine:
2030 * Weird errors, like selecting the wrong keyframe range (see #39207), occur.
2031 * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd.
2032 */
2033 a = BKE_fcurve_bezt_binarysearch_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact);
2034 const BezTriple *bezt = bezts + a;
2035
2036 if (exact) {
2037 /* Index returned must be interpreted differently when it sits on top of an existing keyframe
2038 * - That keyframe is the start of the segment we need (see action_bug_2.blend in #39207).
2039 */
2040 return bezt->vec[1][1];
2041 }
2042
2043 /* Index returned refers to the keyframe that the eval-time occurs *before*
2044 * - hence, that keyframe marks the start of the segment we're dealing with.
2045 */
2046 const BezTriple *prevbezt = (a > 0) ? (bezt - 1) : bezt;
2047
2048 /* Use if the key is directly on the frame, in rare cases this is needed else we get 0.0 instead.
2049 * XXX: consult #39207 for examples of files where failure of these checks can cause issues. */
2050 if (fabsf(bezt->vec[1][0] - evaltime) < eps) {
2051 return bezt->vec[1][1];
2052 }
2053
2054 if (evaltime < prevbezt->vec[1][0] || bezt->vec[1][0] < evaltime) {
2055 if (G.debug & G_DEBUG) {
2056 printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n",
2057 prevbezt->vec[1][0],
2058 bezt->vec[1][0],
2059 evaltime,
2060 fabsf(bezt->vec[1][0] - evaltime));
2061 }
2062 return 0.0f;
2063 }
2064
2065 /* Evaluation-time occurs within the interval defined by these two keyframes. */
2066 const float begin = prevbezt->vec[1][1];
2067 const float change = bezt->vec[1][1] - prevbezt->vec[1][1];
2068 const float duration = bezt->vec[1][0] - prevbezt->vec[1][0];
2069 const float time = evaltime - prevbezt->vec[1][0];
2070 const float amplitude = prevbezt->amplitude;
2071 const float period = prevbezt->period;
2072
2073 /* Value depends on interpolation mode. */
2074 if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) || (duration == 0))
2075 {
2076 /* Constant (evaltime not relevant, so no interpolation needed). */
2077 return prevbezt->vec[1][1];
2078 }
2079
2080 switch (prevbezt->ipo) {
2081 /* Interpolation ...................................... */
2082 case BEZT_IPO_BEZ: {
2083 float v1[2], v2[2], v3[2], v4[2], opl[32];
2084
2085 /* Bezier interpolation. */
2086 /* (v1, v2) are the first keyframe and its 2nd handle. */
2087 v1[0] = prevbezt->vec[1][0];
2088 v1[1] = prevbezt->vec[1][1];
2089 v2[0] = prevbezt->vec[2][0];
2090 v2[1] = prevbezt->vec[2][1];
2091 /* (v3, v4) are the last keyframe's 1st handle + the last keyframe. */
2092 v3[0] = bezt->vec[0][0];
2093 v3[1] = bezt->vec[0][1];
2094 v4[0] = bezt->vec[1][0];
2095 v4[1] = bezt->vec[1][1];
2096
2097 if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON &&
2098 fabsf(v3[1] - v4[1]) < FLT_EPSILON)
2099 {
2100 /* Optimization: If all the handles are flat/at the same values,
2101 * the value is simply the shared value (see #40372 -> F91346).
2102 */
2103 return v1[1];
2104 }
2105 /* Adjust handles so that they don't overlap (forming a loop). */
2106 BKE_fcurve_correct_bezpart(v1, v2, v3, v4);
2107
2108 /* Try to get a value for this position - if failure, try another set of points. */
2109 if (!findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl)) {
2110 if (G.debug & G_DEBUG) {
2111 printf(" ERROR: findzero() failed at %f with %f %f %f %f\n",
2112 evaltime,
2113 v1[0],
2114 v2[0],
2115 v3[0],
2116 v4[0]);
2117 }
2118 return 0.0;
2119 }
2120
2121 berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1);
2122 return opl[0];
2123 }
2124 case BEZT_IPO_LIN:
2125 /* Linear - simply linearly interpolate between values of the two keyframes. */
2126 return BLI_easing_linear_ease(time, begin, change, duration);
2127
2128 /* Easing ............................................ */
2129 case BEZT_IPO_BACK:
2130 switch (prevbezt->easing) {
2131 case BEZT_IPO_EASE_IN:
2132 return BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back);
2133 case BEZT_IPO_EASE_OUT:
2134 return BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
2136 return BLI_easing_back_ease_in_out(time, begin, change, duration, prevbezt->back);
2137
2138 default: /* Default/Auto: same as ease out. */
2139 return BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
2140 }
2141 break;
2142
2143 case BEZT_IPO_BOUNCE:
2144 switch (prevbezt->easing) {
2145 case BEZT_IPO_EASE_IN:
2146 return BLI_easing_bounce_ease_in(time, begin, change, duration);
2147 case BEZT_IPO_EASE_OUT:
2148 return BLI_easing_bounce_ease_out(time, begin, change, duration);
2150 return BLI_easing_bounce_ease_in_out(time, begin, change, duration);
2151
2152 default: /* Default/Auto: same as ease out. */
2153 return BLI_easing_bounce_ease_out(time, begin, change, duration);
2154 }
2155 break;
2156
2157 case BEZT_IPO_CIRC:
2158 switch (prevbezt->easing) {
2159 case BEZT_IPO_EASE_IN:
2160 return BLI_easing_circ_ease_in(time, begin, change, duration);
2161 case BEZT_IPO_EASE_OUT:
2162 return BLI_easing_circ_ease_out(time, begin, change, duration);
2164 return BLI_easing_circ_ease_in_out(time, begin, change, duration);
2165
2166 default: /* Default/Auto: same as ease in. */
2167 return BLI_easing_circ_ease_in(time, begin, change, duration);
2168 }
2169 break;
2170
2171 case BEZT_IPO_CUBIC:
2172 switch (prevbezt->easing) {
2173 case BEZT_IPO_EASE_IN:
2174 return BLI_easing_cubic_ease_in(time, begin, change, duration);
2175 case BEZT_IPO_EASE_OUT:
2176 return BLI_easing_cubic_ease_out(time, begin, change, duration);
2178 return BLI_easing_cubic_ease_in_out(time, begin, change, duration);
2179
2180 default: /* Default/Auto: same as ease in. */
2181 return BLI_easing_cubic_ease_in(time, begin, change, duration);
2182 }
2183 break;
2184
2185 case BEZT_IPO_ELASTIC:
2186 switch (prevbezt->easing) {
2187 case BEZT_IPO_EASE_IN:
2188 return BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period);
2189 case BEZT_IPO_EASE_OUT:
2190 return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
2192 return BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period);
2193
2194 default: /* Default/Auto: same as ease out. */
2195 return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
2196 }
2197 break;
2198
2199 case BEZT_IPO_EXPO:
2200 switch (prevbezt->easing) {
2201 case BEZT_IPO_EASE_IN:
2202 return BLI_easing_expo_ease_in(time, begin, change, duration);
2203 case BEZT_IPO_EASE_OUT:
2204 return BLI_easing_expo_ease_out(time, begin, change, duration);
2206 return BLI_easing_expo_ease_in_out(time, begin, change, duration);
2207
2208 default: /* Default/Auto: same as ease in. */
2209 return BLI_easing_expo_ease_in(time, begin, change, duration);
2210 }
2211 break;
2212
2213 case BEZT_IPO_QUAD:
2214 switch (prevbezt->easing) {
2215 case BEZT_IPO_EASE_IN:
2216 return BLI_easing_quad_ease_in(time, begin, change, duration);
2217 case BEZT_IPO_EASE_OUT:
2218 return BLI_easing_quad_ease_out(time, begin, change, duration);
2220 return BLI_easing_quad_ease_in_out(time, begin, change, duration);
2221
2222 default: /* Default/Auto: same as ease in. */
2223 return BLI_easing_quad_ease_in(time, begin, change, duration);
2224 }
2225 break;
2226
2227 case BEZT_IPO_QUART:
2228 switch (prevbezt->easing) {
2229 case BEZT_IPO_EASE_IN:
2230 return BLI_easing_quart_ease_in(time, begin, change, duration);
2231 case BEZT_IPO_EASE_OUT:
2232 return BLI_easing_quart_ease_out(time, begin, change, duration);
2234 return BLI_easing_quart_ease_in_out(time, begin, change, duration);
2235
2236 default: /* Default/Auto: same as ease in. */
2237 return BLI_easing_quart_ease_in(time, begin, change, duration);
2238 }
2239 break;
2240
2241 case BEZT_IPO_QUINT:
2242 switch (prevbezt->easing) {
2243 case BEZT_IPO_EASE_IN:
2244 return BLI_easing_quint_ease_in(time, begin, change, duration);
2245 case BEZT_IPO_EASE_OUT:
2246 return BLI_easing_quint_ease_out(time, begin, change, duration);
2248 return BLI_easing_quint_ease_in_out(time, begin, change, duration);
2249
2250 default: /* Default/Auto: same as ease in. */
2251 return BLI_easing_quint_ease_in(time, begin, change, duration);
2252 }
2253 break;
2254
2255 case BEZT_IPO_SINE:
2256 switch (prevbezt->easing) {
2257 case BEZT_IPO_EASE_IN:
2258 return BLI_easing_sine_ease_in(time, begin, change, duration);
2259 case BEZT_IPO_EASE_OUT:
2260 return BLI_easing_sine_ease_out(time, begin, change, duration);
2262 return BLI_easing_sine_ease_in_out(time, begin, change, duration);
2263
2264 default: /* Default/Auto: same as ease in. */
2265 return BLI_easing_sine_ease_in(time, begin, change, duration);
2266 }
2267 break;
2268
2269 default:
2270 return prevbezt->vec[1][1];
2271 }
2272
2273 return 0.0f;
2274}
2275
2276/* Calculate F-Curve value for 'evaltime' using #BezTriple keyframes. */
2277static float fcurve_eval_keyframes(const FCurve *fcu, const BezTriple *bezts, float evaltime)
2278{
2279 if (evaltime <= bezts->vec[1][0]) {
2280 return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, 0, +1);
2281 }
2282
2283 const BezTriple *lastbezt = bezts + fcu->totvert - 1;
2284 if (lastbezt->vec[1][0] <= evaltime) {
2285 return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, fcu->totvert - 1, -1);
2286 }
2287
2288 return fcurve_eval_keyframes_interpolate(fcu, bezts, evaltime);
2289}
2290
2291/* Calculate F-Curve value for 'evaltime' using #FPoint samples. */
2292static float fcurve_eval_samples(const FCurve *fcu, const FPoint *fpts, float evaltime)
2293{
2294 float cvalue = 0.0f;
2295
2296 /* Get pointers. */
2297 const FPoint *prevfpt = fpts;
2298 const FPoint *lastfpt = prevfpt + fcu->totvert - 1;
2299
2300 /* Evaluation time at or past endpoints? */
2301 if (prevfpt->vec[0] >= evaltime) {
2302 /* Before or on first sample, so just extend value. */
2303 cvalue = prevfpt->vec[1];
2304 }
2305 else if (lastfpt->vec[0] <= evaltime) {
2306 /* After or on last sample, so just extend value. */
2307 cvalue = lastfpt->vec[1];
2308 }
2309 else {
2310 float t = fabsf(evaltime - floorf(evaltime));
2311
2312 /* Find the one on the right frame (assume that these are spaced on 1-frame intervals). */
2313 const FPoint *fpt = prevfpt + (int(evaltime) - int(prevfpt->vec[0]));
2314
2315 /* If not exactly on the frame, perform linear interpolation with the next one. */
2316 if (t != 0.0f && t < 1.0f) {
2317 cvalue = interpf(fpt->vec[1], (fpt + 1)->vec[1], 1.0f - t);
2318 }
2319 else {
2320 cvalue = fpt->vec[1];
2321 }
2322 }
2323
2324 return cvalue;
2325}
2326
2328
2329/* -------------------------------------------------------------------- */
2332
2333/* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime")
2334 * NOTE: this is also used for drivers.
2335 */
2336static float evaluate_fcurve_ex(const FCurve *fcu, float evaltime, float cvalue)
2337{
2338 /* Evaluate modifiers which modify time to evaluate the base curve at. */
2339 FModifiersStackStorage storage;
2342 storage.buffer = alloca(storage.modifier_count * storage.size_per_modifier);
2343
2344 const float devaltime = evaluate_time_fmodifiers(
2345 &storage, &fcu->modifiers, fcu, cvalue, evaltime);
2346
2347 /* Evaluate curve-data
2348 * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying
2349 * F-Curve modifier on the stack requested the curve to be evaluated at.
2350 */
2351 if (fcu->bezt) {
2352 cvalue = fcurve_eval_keyframes(fcu, fcu->bezt, devaltime);
2353 }
2354 else if (fcu->fpt) {
2355 cvalue = fcurve_eval_samples(fcu, fcu->fpt, devaltime);
2356 }
2357
2358 /* Evaluate modifiers. */
2359 evaluate_value_fmodifiers(&storage, &fcu->modifiers, fcu, &cvalue, devaltime);
2360
2361 /* If curve can only have integral values, perform truncation (i.e. drop the decimal part)
2362 * here so that the curve can be sampled correctly.
2363 */
2364 if (fcu->flag & FCURVE_INT_VALUES) {
2365 cvalue = floorf(cvalue + 0.5f);
2366 }
2367
2368 return cvalue;
2369}
2370
2371float evaluate_fcurve(const FCurve *fcu, float evaltime)
2372{
2373 BLI_assert(fcu->driver == nullptr);
2374
2375 return evaluate_fcurve_ex(fcu, evaltime, 0.0);
2376}
2377
2379{
2380 /* Can be used to evaluate the (key-framed) f-curve only.
2381 * Also works for driver-f-curves when the driver itself is not relevant.
2382 * E.g. when inserting a keyframe in a driver f-curve. */
2383 return evaluate_fcurve_ex(fcu, evaltime, 0.0);
2384}
2385
2387 FCurve *fcu,
2388 ChannelDriver *driver_orig,
2389 const AnimationEvalContext *anim_eval_context)
2390{
2391 BLI_assert(fcu->driver != nullptr);
2392 float cvalue = 0.0f;
2393 float evaltime = anim_eval_context->eval_time;
2394
2395 /* If there is a driver (only if this F-Curve is acting as 'driver'),
2396 * evaluate it to find value to use as `evaltime` since drivers essentially act as alternative
2397 * input (i.e. in place of 'time') for F-Curves. */
2398 if (fcu->driver) {
2399 /* Evaluation-time now serves as input for the curve. */
2400 evaltime = evaluate_driver(anim_rna, fcu->driver, driver_orig, anim_eval_context);
2401
2402 /* Only do a default 1-1 mapping if it's unlikely that anything else will set a value... */
2403 if (fcu->totvert == 0) {
2404 bool do_linear = true;
2405
2406 /* Out-of-range F-Modifiers will block, as will those which just plain overwrite the values
2407 * XXX: additive is a bit more dicey; it really depends then if things are in range or not...
2408 */
2409 LISTBASE_FOREACH (FModifier *, fcm, &fcu->modifiers) {
2410 /* If there are range-restrictions, we must definitely block #36950. */
2411 if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 ||
2412 (fcm->sfra <= evaltime && fcm->efra >= evaltime))
2413 {
2414 /* Within range: here it probably doesn't matter,
2415 * though we'd want to check on additive. */
2416 }
2417 else {
2418 /* Outside range: modifier shouldn't contribute to the curve here,
2419 * though it does in other areas, so neither should the driver! */
2420 do_linear = false;
2421 }
2422 }
2423
2424 /* Only copy over results if none of the modifiers disagreed with this. */
2425 if (do_linear) {
2426 cvalue = evaltime;
2427 }
2428 }
2429 }
2430
2431 return evaluate_fcurve_ex(fcu, evaltime, cvalue);
2432}
2433
2435{
2436 return fcu->totvert == 0 && fcu->driver == nullptr &&
2438}
2439
2441 FCurve *fcu,
2442 const AnimationEvalContext *anim_eval_context)
2443{
2444 /* Only calculate + set curval (overriding the existing value) if curve has
2445 * any data which warrants this...
2446 */
2447 if (BKE_fcurve_is_empty(fcu)) {
2448 return 0.0f;
2449 }
2450
2451 /* Calculate and set curval (evaluates driver too if necessary). */
2452 float curval;
2453 if (fcu->driver) {
2454 curval = evaluate_fcurve_driver(anim_rna, fcu, fcu->driver, anim_eval_context);
2455 }
2456 else {
2457 curval = evaluate_fcurve(fcu, anim_eval_context->eval_time);
2458 }
2459 fcu->curval = curval; /* Debug display only, not thread safe! */
2460 return curval;
2461}
2462
2464
2465/* -------------------------------------------------------------------- */
2468
2470{
2471 /* Write all modifiers first (for faster reloading) */
2472 BLO_write_struct_list(writer, FModifier, fmodifiers);
2473
2474 /* Modifiers */
2475 LISTBASE_FOREACH (FModifier *, fcm, fmodifiers) {
2476 const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
2477
2478 /* Write the specific data */
2479 if (fmi && fcm->data) {
2480 /* firstly, just write the plain fmi->data struct */
2481 BLO_write_struct_by_name(writer, fmi->struct_name, fcm->data);
2482
2483 /* do any modifier specific stuff */
2484 switch (fcm->type) {
2486 FMod_Generator *data = static_cast<FMod_Generator *>(fcm->data);
2487
2488 /* write coefficients array */
2489 if (data->coefficients) {
2490 BLO_write_float_array(writer, data->arraysize, data->coefficients);
2491 }
2492
2493 break;
2494 }
2496 FMod_Envelope *data = static_cast<FMod_Envelope *>(fcm->data);
2497
2498 /* write envelope data */
2499 if (data->data) {
2500 BLO_write_struct_array(writer, FCM_EnvelopeData, data->totvert, data->data);
2501 }
2502
2503 break;
2504 }
2505 }
2506 }
2507 }
2508}
2509
2511{
2512 LISTBASE_FOREACH (FModifier *, fcm, fmodifiers) {
2513 const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
2514
2515 /* relink general data */
2516 if (fmi) {
2517 fcm->data = BLO_read_struct_by_name_array(reader, fmi->struct_name, 1, fcm->data);
2518 }
2519 else {
2520 /* This can happen when the blend file has data for a modifier that doesn't exist in this
2521 * Blender version (when the blend file is newer). */
2524 RPT_("F-Curve modifier lost on '%s[%d]' because it has an unknown type"),
2525 curve->rna_path,
2526 curve->array_index);
2527 fcm->data = nullptr;
2528 }
2529 fcm->curve = curve;
2530
2531 /* do relinking of data for specific types */
2532 switch (fcm->type) {
2534 FMod_Generator *data = (FMod_Generator *)fcm->data;
2535 BLO_read_float_array(reader, data->arraysize, &data->coefficients);
2536 break;
2537 }
2539 FMod_Envelope *data = (FMod_Envelope *)fcm->data;
2540
2541 BLO_read_struct_array(reader, FCM_EnvelopeData, data->totvert, &data->data);
2542
2543 break;
2544 }
2545 }
2546 }
2547}
2548
2550{
2551 /* curve data */
2552 if (fcu->bezt) {
2553 BLO_write_struct_array(writer, BezTriple, fcu->totvert, fcu->bezt);
2554 }
2555 if (fcu->fpt) {
2556 BLO_write_struct_array(writer, FPoint, fcu->totvert, fcu->fpt);
2557 }
2558
2559 if (fcu->rna_path) {
2560 BLO_write_string(writer, fcu->rna_path);
2561 }
2562
2563 /* driver data */
2564 if (fcu->driver) {
2565 ChannelDriver *driver = fcu->driver;
2566
2567 BLO_write_struct(writer, ChannelDriver, driver);
2568
2569 /* variables */
2570 BLO_write_struct_list(writer, DriverVar, &driver->variables);
2571 LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
2573 if (dtar->rna_path) {
2574 BLO_write_string(writer, dtar->rna_path);
2575 }
2576 }
2578 }
2579 }
2580
2581 /* write F-Modifiers */
2583}
2584
2586{
2587 BLO_write_struct_list(writer, FCurve, fcurves);
2588 LISTBASE_FOREACH (FCurve *, fcu, fcurves) {
2589 BKE_fcurve_blend_write_data(writer, fcu);
2590 }
2591}
2592
2594{
2595 /* curve data */
2596 BLO_read_struct_array(reader, BezTriple, fcu->totvert, &fcu->bezt);
2597 BLO_read_struct_array(reader, FPoint, fcu->totvert, &fcu->fpt);
2598
2599 /* rna path */
2600 BLO_read_string(reader, &fcu->rna_path);
2601
2602 /* group */
2603 BLO_read_struct(reader, bActionGroup, &fcu->grp);
2604
2605 /* clear disabled flag - allows disabled drivers to be tried again (#32155),
2606 * but also means that another method for "reviving disabled F-Curves" exists
2607 */
2608 fcu->flag &= ~FCURVE_DISABLED;
2609
2610 /* driver */
2611 BLO_read_struct(reader, ChannelDriver, &fcu->driver);
2612 if (fcu->driver) {
2613 ChannelDriver *driver = fcu->driver;
2614
2615 /* Compiled expression data will need to be regenerated
2616 * (old pointer may still be set here). */
2617 driver->expr_comp = nullptr;
2618 driver->expr_simple = nullptr;
2619
2620 /* Give the driver a fresh chance - the operating environment may be different now
2621 * (addons, etc. may be different) so the driver namespace may be sane now #32155. */
2623
2624 /* relink variables, targets and their paths */
2625 BLO_read_struct_list(reader, DriverVar, &driver->variables);
2626 LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
2628 /* only relink the targets being used */
2629 if (tarIndex < dvar->num_targets) {
2630 BLO_read_string(reader, &dtar->rna_path);
2631 }
2632 else {
2633 dtar->rna_path = nullptr;
2634 dtar->id = nullptr;
2635 }
2636 }
2638 }
2639 }
2640
2641 /* modifiers */
2643 BKE_fmodifiers_blend_read_data(reader, &fcu->modifiers, fcu);
2644}
2645
2647{
2648 /* Link F-Curve data to F-Curve again (non ID-libraries). */
2649 LISTBASE_FOREACH (FCurve *, fcu, fcurves) {
2650 BKE_fcurve_blend_read_data(reader, fcu);
2651 }
2652}
2653
Functions and classes to work with Actions.
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:83
@ NURB_HANDLE_TEST_EACH
Definition BKE_curve.hh:61
@ NURB_HANDLE_TEST_KNOT_ONLY
Definition BKE_curve.hh:71
void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
Definition curve.cc:3891
void BKE_nurb_bezt_handle_test(BezTriple *bezt, eBezTriple_Flag__Alias sel_flag, const eNurbHandleTest_Mode handle_mode, bool use_around_local)
Definition curve.cc:4048
@ FMI_TYPE_GENERATE_CURVE
Definition BKE_fcurve.hh:96
const FModifierTypeInfo * get_fmodifier_typeinfo(int type)
float evaluate_time_fmodifiers(FModifiersStackStorage *storage, const ListBase *modifiers, const FCurve *fcu, float cvalue, float evaltime)
void copy_fmodifiers(ListBase *dst, const ListBase *src)
uint evaluate_fmodifiers_storage_size_per_modifier(const ListBase *modifiers)
eFCU_Cycle_Type
@ FCU_CYCLE_OFFSET
@ FCU_CYCLE_NONE
@ FCU_CYCLE_PERFECT
void evaluate_value_fmodifiers(FModifiersStackStorage *storage, const ListBase *modifiers, const FCurve *fcu, float *cvalue, float evaltime)
bool list_has_suitable_fmodifier(const ListBase *modifiers, int mtype, short acttype)
float(* FcuSampleFunc)(FCurve *fcu, void *data, float evaltime)
#define BEZT_BINARYSEARCH_THRESH
void free_fmodifiers(ListBase *modifiers)
const FModifierTypeInfo * fmodifier_get_typeinfo(const FModifier *fcm)
#define DRIVER_TARGETS_LOOPER_BEGIN(dvar)
float evaluate_driver(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, struct ChannelDriver *driver_orig, const struct AnimationEvalContext *anim_eval_context)
struct ChannelDriver * fcurve_copy_driver(const struct ChannelDriver *driver)
void fcurve_free_driver(struct FCurve *fcu)
#define DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
#define DRIVER_TARGETS_LOOPER_END
@ G_DEBUG
@ IDWALK_CB_NOP
#define BKE_LIB_FOREACHID_PROCESS_ID(data_, id_, cb_flag_)
bool BKE_nlastrip_has_curves_for_property(const PointerRNA *ptr, const PropertyRNA *prop)
@ RPT_WARNING
Definition BKE_report.hh:38
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
float BLI_easing_sine_ease_in(float time, float begin, float change, float duration)
Definition easing.cc:348
float BLI_easing_back_ease_out(float time, float begin, float change, float duration, float overshoot)
Definition easing.cc:25
float BLI_easing_linear_ease(float time, float begin, float change, float duration)
Definition easing.cc:282
float BLI_easing_bounce_ease_in_out(float time, float begin, float change, float duration)
Definition easing.cc:66
float BLI_easing_quint_ease_out(float time, float begin, float change, float duration)
Definition easing.cc:334
float BLI_easing_quart_ease_in_out(float time, float begin, float change, float duration)
Definition easing.cc:320
float BLI_easing_circ_ease_in_out(float time, float begin, float change, float duration)
Definition easing.cc:87
float BLI_easing_quart_ease_out(float time, float begin, float change, float duration)
Definition easing.cc:314
float BLI_easing_bounce_ease_in(float time, float begin, float change, float duration)
Definition easing.cc:61
float BLI_easing_circ_ease_in(float time, float begin, float change, float duration)
Definition easing.cc:75
float BLI_easing_expo_ease_in(float time, float begin, float change, float duration)
Definition easing.cc:255
float BLI_easing_expo_ease_out(float time, float begin, float change, float duration)
Definition easing.cc:263
float BLI_easing_elastic_ease_in(float time, float begin, float change, float duration, float amplitude, float period)
Definition easing.cc:146
float BLI_easing_quad_ease_in_out(float time, float begin, float change, float duration)
Definition easing.cc:299
float BLI_easing_elastic_ease_out(float time, float begin, float change, float duration, float amplitude, float period)
Definition easing.cc:179
float BLI_easing_cubic_ease_in(float time, float begin, float change, float duration)
Definition easing.cc:96
float BLI_easing_elastic_ease_in_out(float time, float begin, float change, float duration, float amplitude, float period)
Definition easing.cc:211
float BLI_easing_quint_ease_in(float time, float begin, float change, float duration)
Definition easing.cc:329
float BLI_easing_sine_ease_out(float time, float begin, float change, float duration)
Definition easing.cc:353
float BLI_easing_bounce_ease_out(float time, float begin, float change, float duration)
Definition easing.cc:43
float BLI_easing_quad_ease_in(float time, float begin, float change, float duration)
Definition easing.cc:287
float BLI_easing_quad_ease_out(float time, float begin, float change, float duration)
Definition easing.cc:293
float BLI_easing_circ_ease_out(float time, float begin, float change, float duration)
Definition easing.cc:81
float BLI_easing_cubic_ease_out(float time, float begin, float change, float duration)
Definition easing.cc:102
float BLI_easing_back_ease_in(float time, float begin, float change, float duration, float overshoot)
Definition easing.cc:18
float BLI_easing_quint_ease_in_out(float time, float begin, float change, float duration)
Definition easing.cc:339
float BLI_easing_expo_ease_in_out(float time, float begin, float change, float duration)
Definition easing.cc:271
float BLI_easing_quart_ease_in(float time, float begin, float change, float duration)
Definition easing.cc:308
float BLI_easing_back_ease_in_out(float time, float begin, float change, float duration, float overshoot)
Definition easing.cc:32
float BLI_easing_cubic_ease_in_out(float time, float begin, float change, float duration)
Definition easing.cc:108
float BLI_easing_sine_ease_in_out(float time, float begin, float change, float duration)
Definition easing.cc:358
#define GSET_ITER_INDEX(gs_iter_, gset_, i_)
Definition BLI_ghash.h:472
struct GSet GSet
Definition BLI_ghash.h:337
GSet * BLI_gset_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
unsigned int BLI_gset_len(const GSet *gs) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:954
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition BLI_ghash.h:455
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
bool BLI_gset_add(GSet *gs, void *key)
Definition BLI_ghash.cc:966
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
ListBase BLI_listbase_from_link(Link *some_link)
Definition listbase.cc:800
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
MINLINE float max_fff(float a, float b, float c)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
MINLINE double sqrt3d(double d)
MINLINE float interpf(float target, float origin, float t)
MINLINE float min_fff(float a, float b, float c)
MINLINE int clamp_i(int value, int min, int max)
MINLINE int compare_ff_relative(float a, float b, float max_diff, int max_ulps)
MINLINE void swap_v2_v2(float a[2], float b[2])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], float t)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void add_v3_v3(float r[3], const float a[3])
bool BLI_rctf_is_valid(const struct rctf *rect)
int BLI_sortutil_cmp_float(const void *a_, const void *b_)
Definition sort_utils.cc:25
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.cc:30
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
void BLI_uniquename(const struct ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_maxncpy) ATTR_NONNULL(1
unsigned int uint
#define CLAMP_MAX(a, c)
#define POINTER_FROM_INT(i)
#define POINTER_AS_INT(i)
#define UNLIKELY(x)
#define ELEM(...)
#define IS_EQT(a, b, c)
#define STREQ(a, b)
#define CLAMP_MIN(a, b)
void BLO_write_float_array(BlendWriter *writer, int64_t num, const float *data_ptr)
BlendFileReadReport * BLO_read_data_reports(BlendDataReader *reader)
Definition readfile.cc:5978
void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr)
void BLO_read_float_array(BlendDataReader *reader, int64_t array_size, float **ptr_p)
Definition readfile.cc:5809
#define BLO_write_struct(writer, struct_name, data_ptr)
void * BLO_read_struct_by_name_array(BlendDataReader *reader, const char *struct_name, int64_t items_num, const void *old_address)
Definition readfile.cc:5719
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:5828
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define BLO_write_struct_list(writer, struct_name, list_ptr)
#define BLO_read_struct(reader, struct_name, ptr_p)
void BLO_reportf_wrap(BlendFileReadReport *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLT_I18NCONTEXT_ID_ACTION
#define RPT_(msgid)
#define CTX_DATA_(context, msgid)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:189
@ AGRP_PROTECTED
@ FCM_EXTRAPOLATE_CYCLIC
@ FCM_EXTRAPOLATE_CYCLIC_OFFSET
@ FCM_GENERATOR_ADDITIVE
@ FMODIFIER_TYPE_CYCLES
@ FMODIFIER_TYPE_STEPPED
@ FMODIFIER_TYPE_FN_GENERATOR
@ FMODIFIER_TYPE_NOISE
@ FMODIFIER_TYPE_GENERATOR
@ FMODIFIER_TYPE_ENVELOPE
@ FMODIFIER_FLAG_MUTED
@ FMODIFIER_FLAG_USEINFLUENCE
@ FMODIFIER_FLAG_DISABLED
@ FMODIFIER_FLAG_RANGERESTRICT
@ DRIVER_FLAG_INVALID
@ DRIVER_FLAG_PYTHON_BLOCKED
#define FCURVE_ACTIVE_KEYFRAME_NONE
@ FCURVE_DISABLED
@ FCURVE_INT_VALUES
@ FCURVE_DISCRETE_VALUES
@ FCURVE_PROTECTED
@ FCURVE_EXTRAPOLATE_CONSTANT
@ FCURVE_SMOOTH_NONE
@ HD_AUTO_ANIM
@ HD_AUTOTYPE_NORMAL
@ HD_AUTOTYPE_LOCKED_FINAL
@ BEZT_IPO_ELASTIC
@ BEZT_IPO_CIRC
@ BEZT_IPO_QUART
@ BEZT_IPO_BACK
@ BEZT_IPO_BOUNCE
@ BEZT_IPO_CUBIC
@ BEZT_IPO_EXPO
@ BEZT_IPO_CONST
@ BEZT_IPO_BEZ
@ BEZT_IPO_LIN
@ BEZT_IPO_SINE
@ BEZT_IPO_QUAD
@ BEZT_IPO_QUINT
@ BEZT_IPO_EASE_OUT
@ BEZT_IPO_EASE_IN
@ BEZT_IPO_EASE_IN_OUT
eBezTriple_Flag
#define BEZT_IS_AUTOH(bezt)
#define BEZT_ISSEL_ANY(bezt)
#define BEZT_DESEL_ALL(bezt)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
void BKE_fcurve_deduplicate_keys(FCurve *fcu)
#define SMALL
bool BKE_fcurve_is_cyclic(const FCurve *fcu)
void BKE_fcurve_keyframe_move_time_with_handles(BezTriple *keyframe, const float new_time)
float * BKE_fcurves_calc_keyed_frames(FCurve **fcurve_array, int fcurve_array_len, int *r_frames_len)
FCurve * BKE_fcurve_copy(const FCurve *fcu)
bool BKE_fcurve_calc_range(const FCurve *fcu, float *r_min, float *r_max, const bool selected_keys_only)
FCurve * BKE_fcurve_create()
void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data)
void BKE_fcurve_blend_write_data(BlendWriter *writer, FCurve *fcu)
bool BKE_fcurve_is_keyframable(const FCurve *fcu)
int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[], const float frame, const int arraylen, bool *r_replace)
void BKE_fmodifier_name_set(FModifier *fcm, const char *name)
static void calculate_bezt_bounds_y(BezTriple *bezt_array, const int index_range[2], const bool selected_keys_only, const bool include_handles, float *r_min, float *r_max)
void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_handle)
FCurve * BKE_fcurve_find_by_rna_context_ui(bContext *, const PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **r_animdata, bAction **r_action, bool *r_driven, bool *r_special)
static void calculate_bezt_bounds_x(BezTriple *bezt_array, const int index_range[2], const bool include_handles, float *r_min, float *r_max)
void BKE_fcurve_delete_keys(FCurve *fcu, blender::uint2 index_range)
static BezTriple * cycle_offset_triple(bool cycle, BezTriple *out, const BezTriple *in, const BezTriple *from, const BezTriple *to)
FCurve * BKE_animadata_fcurve_find_by_rna_path(AnimData *animdata, const char *rna_path, int rna_index, bAction **r_action, bool *r_driven)
int BKE_fcurve_active_keyframe_index(const FCurve *fcu)
void BKE_fcurve_handles_recalc(FCurve *fcu)
float * BKE_fcurves_calc_keyed_frames_ex(FCurve **fcurve_array, int fcurve_array_len, const float interval, int *r_frames_len)
bool test_time_fcurve(FCurve *fcu)
static float fcurve_eval_keyframes_interpolate(const FCurve *fcu, const BezTriple *bezts, float evaltime)
static float fcurve_eval_samples(const FCurve *fcu, const FPoint *fpts, float evaltime)
static void berekeny(float f1, float f2, float f3, float f4, float *o, int b)
void BKE_fcurve_handles_recalc_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag)
FCurve * BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[])
void BKE_fcurve_blend_write_listbase(BlendWriter *writer, ListBase *fcurves)
static float fcurve_eval_keyframes(const FCurve *fcu, const BezTriple *bezts, float evaltime)
float evaluate_fcurve_only_curve(const FCurve *fcu, float evaltime)
bool BKE_fcurve_is_empty(const FCurve *fcu)
float fcurve_samplingcb_evalcurve(FCurve *fcu, void *, float evaltime)
bool BKE_fcurve_delete_keys_selected(FCurve *fcu)
FCurve * BKE_fcurve_find_by_rna(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **r_adt, bAction **r_action, bool *r_driven, bool *r_special)
void BKE_fmodifiers_blend_write(BlendWriter *writer, ListBase *fmodifiers)
void BKE_fcurve_blend_read_data_listbase(BlendDataReader *reader, ListBase *fcurves)
static int solve_cubic(double c0, double c1, double c2, double c3, float *o)
eFCU_Cycle_Type BKE_fcurve_get_cycle_type(const FCurve *fcu)
static int findzero(float x, float q0, float q1, float q2, float q3, float *o)
bool BKE_fcurve_calc_bounds(const FCurve *fcu, const bool selected_keys_only, const bool include_handles, const float frame_range[2], rctf *r_bounds)
float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, ChannelDriver *driver_orig, const AnimationEvalContext *anim_eval_context)
void BKE_fcurve_deselect_all_keys(FCurve &fcu)
void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt)
FCurve * BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_index)
bool BKE_fcurve_is_protected(const FCurve *fcu)
static void fcurve_bezt_free(FCurve *fcu)
void BKE_fcurve_keyframe_move_value_with_handles(BezTriple *keyframe, const float new_value)
void BKE_fmodifiers_blend_read_data(BlendDataReader *reader, ListBase *fmodifiers, FCurve *curve)
bool BKE_fcurve_bezt_subdivide_handles(BezTriple *bezt, BezTriple *prev, BezTriple *next, float *r_pdelta)
bool BKE_fcurve_are_keyframes_usable(const FCurve *fcu)
void BKE_fcurves_free(ListBase *list)
static float fcurve_eval_keyframes_extrapolate(const FCurve *fcu, const BezTriple *bezts, float evaltime, int endpoint_offset, int direction_to_neighbor)
void BKE_fcurves_copy(ListBase *dst, ListBase *src)
float evaluate_fcurve(const FCurve *fcu, float evaltime)
void BKE_fcurve_rnapath_set(FCurve &fcu, blender::StringRef rna_path)
static void init_unbaked_bezt_data(BezTriple *bezt)
void BKE_fcurve_merge_duplicate_keys(FCurve *fcu, const int sel_flag, const bool use_handle)
bool BKE_fcurve_has_selected_control_points(const FCurve *fcu)
float calculate_fcurve(PathResolvedRNA *anim_rna, FCurve *fcu, const AnimationEvalContext *anim_eval_context)
void BKE_fcurve_free(FCurve *fcu)
static bool calculate_fpt_bounds(const FCurve *fcu, const float frame_range[2], rctf *r_bounds)
static bool get_bounding_bezt_indices(const FCurve *fcu, const bool selected_keys_only, const float frame_range[2], int *r_first, int *r_last)
void sort_time_fcurve(FCurve *fcu)
void BKE_fcurve_bezt_resize(FCurve *fcu, const int new_totvert)
FCurve * id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *prop_name, int index, bool *r_driven)
static bool calculate_bezt_bounds(const FCurve *fcu, const bool selected_keys_only, const bool include_handles, const float frame_range[2], rctf *r_bounds)
void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end)
void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb)
BezTriple * BKE_bezier_array_merge(const BezTriple *a, const int size_a, const BezTriple *b, const int size_b, int *r_merged_size)
void BKE_fcurve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
void BKE_fcurve_blend_read_data(BlendDataReader *reader, FCurve *fcu)
void BKE_fcurve_delete_key(FCurve *fcu, int index)
static int BKE_fcurve_bezt_binarysearch_index_ex(const BezTriple array[], const float frame, const int arraylen, const float threshold, bool *r_replace)
static float evaluate_fcurve_ex(const FCurve *fcu, float evaltime, float cvalue)
void BKE_fcurve_delete_keys_all(FCurve *fcu)
iter begin(iter)
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v2
float evaltime
constexpr int64_t size() const
constexpr const char * data() const
nullptr float
#define SELECT
#define offsetof(t, d)
#define in
#define out
#define printf(...)
#define round
#define cos
#define abs
#define floor
#define sqrt
#define acos
#define LOG(level)
Definition log.h:97
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static ulong * next
#define G(x, y, z)
FCurve * fcurve_find_in_action_slot(bAction *act, slot_handle_t slot_handle, const FCurveDescriptor &fcurve_descriptor)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
VecBase< uint32_t, 2 > uint2
const btScalar eps
Definition poly34.cpp:11
const char * name
#define floorf
#define fabsf
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_property_animateable(const PointerRNA *ptr, PropertyRNA *prop_orig)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
const char * RNA_property_identifier(const PropertyRNA *prop)
std::optional< std::string > RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
Definition rna_path.cc:1173
#define min(a, b)
Definition sort.cc:36
bAction * action
int32_t slot_handle
ListBase drivers
float vec[3][3]
struct ExprPyLike_Parsed * expr_simple
struct FCurve * next
bActionGroup * grp
float curval
char * rna_path
FPoint * fpt
ChannelDriver * driver
BezTriple * bezt
struct FCurve * prev
short extend
int array_index
unsigned int totvert
int active_keyframe_index
ListBase modifiers
char struct_name[64]
Definition BKE_fcurve.hh:62
char name[64]
float vec[2]
Definition DNA_ID.h:414
void * first
ListBase fcurves
float xmax
float xmin
float ymax
float ymin
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
uint len
PointerRNA * ptr
Definition wm_files.cc:4238