Blender V4.3
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
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#include "ANIM_animdata.hh"
19
20#include "DNA_action_types.h"
21#include "DNA_anim_types.h"
22#include "DNA_object_types.h"
23#include "DNA_text_types.h"
24
25#include "BLI_blenlib.h"
26#include "BLI_easing.h"
27#include "BLI_ghash.h"
28#include "BLI_math_vector.h"
30#include "BLI_sort_utils.h"
31#include "BLI_string_utils.hh"
32#include "BLI_task.hh"
33
34#include "BLT_translation.hh"
35
36#include "BKE_anim_data.hh"
37#include "BKE_animsys.h"
38#include "BKE_context.hh"
39#include "BKE_curve.hh"
40#include "BKE_fcurve.hh"
41#include "BKE_fcurve_driver.h"
42#include "BKE_global.hh"
43#include "BKE_idprop.hh"
44#include "BKE_lib_query.hh"
45#include "BKE_nla.hh"
46#include "BKE_scene.hh"
47
48#include "BLO_read_write.hh"
49
50#include "RNA_access.hh"
51#include "RNA_path.hh"
52
53#include "CLG_log.h"
54
55#define SMALL -1.0e-10
56#define SELECT 1
57
58static CLG_LogRef LOG = {"bke.fcurve"};
59
60/* -------------------------------------------------------------------- */
65{
66 FCurve *fcu = static_cast<FCurve *>(MEM_callocN(sizeof(FCurve), __func__));
67 return fcu;
68}
69
72/* -------------------------------------------------------------------- */
77{
78 if (fcu == nullptr) {
79 return;
80 }
81
82 /* Free curve data. */
83 MEM_SAFE_FREE(fcu->bezt);
84 MEM_SAFE_FREE(fcu->fpt);
85
86 /* Free RNA-path, as this were allocated when getting the path string. */
88
89 /* Free extra data - i.e. modifiers, and driver. */
92
93 /* Free the f-curve itself. */
94 MEM_freeN(fcu);
95}
96
98{
99 /* Sanity check. */
100 if (list == nullptr) {
101 return;
102 }
103
104 /* Free data - no need to call remlink before freeing each curve,
105 * as we store reference to next, and freeing only touches the curve
106 * it's given.
107 */
108 FCurve *fcn = nullptr;
109 for (FCurve *fcu = static_cast<FCurve *>(list->first); fcu; fcu = fcn) {
110 fcn = fcu->next;
111 BKE_fcurve_free(fcu);
112 }
113
114 /* Clear pointers just in case. */
115 BLI_listbase_clear(list);
116}
117
120/* -------------------------------------------------------------------- */
125{
126 /* Sanity check. */
127 if (fcu == nullptr) {
128 return nullptr;
129 }
130
131 /* Make a copy. */
132 FCurve *fcu_d = static_cast<FCurve *>(MEM_dupallocN(fcu));
133
134 fcu_d->next = fcu_d->prev = nullptr;
135 fcu_d->grp = nullptr;
136
137 /* Copy curve data. */
138 fcu_d->bezt = static_cast<BezTriple *>(MEM_dupallocN(fcu_d->bezt));
139 fcu_d->fpt = static_cast<FPoint *>(MEM_dupallocN(fcu_d->fpt));
140
141 /* Copy rna-path. */
142 fcu_d->rna_path = static_cast<char *>(MEM_dupallocN(fcu_d->rna_path));
143
144 /* Copy driver. */
145 fcu_d->driver = fcurve_copy_driver(fcu_d->driver);
146
147 /* Copy modifiers. */
148 copy_fmodifiers(&fcu_d->modifiers, &fcu->modifiers);
149
150 /* Return new data. */
151 return fcu_d;
152}
153
155{
156 /* Sanity checks. */
157 if (ELEM(nullptr, dst, src)) {
158 return;
159 }
160
161 /* Clear destination list first. */
163
164 /* Copy one-by-one. */
165 LISTBASE_FOREACH (FCurve *, sfcu, src) {
166 FCurve *dfcu = BKE_fcurve_copy(sfcu);
167 BLI_addtail(dst, dfcu);
168 }
169}
170
172{
174 fcu.rna_path = BLI_strdupn(rna_path.data(), rna_path.size());
175}
176
177void BKE_fmodifier_name_set(FModifier *fcm, const char *name)
178{
179 /* Copy new Modifier name. */
180 STRNCPY(fcm->name, name);
181
182 /* Set default modifier name when name parameter is an empty string.
183 * Ensure the name is unique. */
185 ListBase list = BLI_listbase_from_link((Link *)fcm);
186 BLI_uniquename(&list,
187 fcm,
189 '.',
190 offsetof(FModifier, name),
191 sizeof(fcm->name));
192}
193
195{
196 ChannelDriver *driver = fcu->driver;
197
198 if (driver != nullptr) {
199 LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
200 /* only used targets */
203 }
205 }
206 }
207}
208
209/* ----------------- Finding F-Curves -------------------------- */
210
212 ID *id, void *data, StructRNA *type, const char *prop_name, int index, bool *r_driven)
213{
214 /* Anim vars */
216
217 /* Rna vars */
218 PropertyRNA *prop;
219
220 if (r_driven) {
221 *r_driven = false;
222 }
223
224 /* Only use the current action ??? */
225 if (ELEM(nullptr, adt, adt->action)) {
226 return nullptr;
227 }
228
229 PointerRNA ptr = RNA_pointer_create(id, type, data);
230 prop = RNA_struct_find_property(&ptr, prop_name);
231 if (prop == nullptr) {
232 return nullptr;
233 }
234
235 const std::optional<std::string> path = RNA_path_from_ID_to_property(&ptr, prop);
236 if (!path) {
237 return nullptr;
238 }
239
240 /* FIXME: The way drivers are handled here (always nullptr-ifying `fcu`) is very weird, this
241 * needs to be re-checked I think?. */
242 bool is_driven = false;
244 adt, path->c_str(), index, nullptr, &is_driven);
245 if (is_driven) {
246 if (r_driven != nullptr) {
247 *r_driven = is_driven;
248 }
249 fcu = nullptr;
250 }
251
252 return fcu;
253}
254
255FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_index)
256{
257 /* Sanity checks. */
258 if (ELEM(nullptr, list, rna_path) || array_index < 0) {
259 return nullptr;
260 }
261
262 /* Check paths of curves, then array indices... */
263 LISTBASE_FOREACH (FCurve *, fcu, list) {
264 /* Check indices first, much cheaper than a string comparison. */
265 /* Simple string-compare (this assumes that they have the same root...) */
266 if (UNLIKELY(fcu->array_index == array_index && fcu->rna_path &&
267 fcu->rna_path[0] == rna_path[0] && STREQ(fcu->rna_path, rna_path)))
268 {
269 return fcu;
270 }
271 }
272
273 return nullptr;
274}
275
278/* -------------------------------------------------------------------- */
282FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[])
283{
284 /* Sanity checks. */
285 if (ELEM(nullptr, fcu_iter, rna_path)) {
286 return nullptr;
287 }
288
289 /* Check paths of curves, then array indices... */
290 for (FCurve *fcu = fcu_iter; fcu; fcu = fcu->next) {
291 /* Simple string-compare (this assumes that they have the same root...) */
292 if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) {
293 return fcu;
294 }
295 }
296
297 return nullptr;
298}
299
301 AnimData *animdata, const char *rna_path, int rna_index, bAction **r_action, bool *r_driven)
302{
303 if (r_driven != nullptr) {
304 *r_driven = false;
305 }
306 if (r_action != nullptr) {
307 *r_action = nullptr;
308 }
309
311 animdata->action, animdata->slot_handle, {rna_path, rna_index});
312 if (fcurve) {
313 /* Action takes priority over drivers. */
314 if (r_action) {
315 *r_action = animdata->action;
316 }
317 return fcurve;
318 }
319
320 /* If not animated, check if driven. */
321 const bool has_drivers = !BLI_listbase_is_empty(&animdata->drivers);
322 if (has_drivers) {
323 FCurve *fcu = BKE_fcurve_find(&animdata->drivers, rna_path, rna_index);
324
325 if (fcu != nullptr) {
326 if (r_driven != nullptr) {
327 *r_driven = true;
328 }
329 return fcu;
330 }
331 }
332
333 return nullptr;
334}
335
337 PropertyRNA *prop,
338 int rnaindex,
339 AnimData **r_adt,
340 bAction **r_action,
341 bool *r_driven,
342 bool *r_special)
343{
345 nullptr, ptr, prop, rnaindex, r_adt, r_action, r_driven, r_special);
346}
347
349 const PointerRNA *ptr,
350 PropertyRNA *prop,
351 int rnaindex,
352 AnimData **r_animdata,
353 bAction **r_action,
354 bool *r_driven,
355 bool *r_special)
356{
357 if (r_animdata != nullptr) {
358 *r_animdata = nullptr;
359 }
360 if (r_action != nullptr) {
361 *r_action = nullptr;
362 }
363 if (r_driven != nullptr) {
364 *r_driven = false;
365 }
366 if (r_special) {
367 *r_special = false;
368 }
369
370 /* Special case for NLA Control Curves... */
372 NlaStrip *strip = static_cast<NlaStrip *>(ptr->data);
373
374 /* Set the special flag, since it cannot be a normal action/driver
375 * if we've been told to start looking here...
376 */
377 if (r_special) {
378 *r_special = true;
379 }
380 if (r_driven) {
381 *r_driven = false;
382 }
383 if (r_animdata) {
384 *r_animdata = nullptr;
385 }
386 if (r_action) {
387 *r_action = nullptr;
388 }
389
390 /* The F-Curve either exists or it doesn't here... */
391 return BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), rnaindex);
392 }
393
394 /* There must be some RNA-pointer + property combo. */
395 if (!prop || !ptr->owner_id || !RNA_property_animateable(ptr, prop)) {
396 return nullptr;
397 }
398
400 if (adt == nullptr) {
401 return nullptr;
402 }
403
404 /* XXX This function call can become a performance bottleneck. */
405 const std::optional<std::string> rna_path = RNA_path_from_ID_to_property(ptr, prop);
406 if (!rna_path) {
407 return nullptr;
408 }
409
410 /* Standard F-Curve from animdata - Animation (Action) or Drivers. */
412 adt, rna_path->c_str(), rnaindex, r_action, r_driven);
413
414 if (fcu != nullptr && r_animdata != nullptr) {
415 *r_animdata = adt;
416 }
417
418 return fcu;
419}
420
423/* -------------------------------------------------------------------- */
427/* Binary search algorithm for finding where to insert BezTriple,
428 * with optional argument for precision required.
429 * Returns the index to insert at (data already at that index will be offset if replace is 0)
430 */
432 const float frame,
433 const int arraylen,
434 const float threshold,
435 bool *r_replace)
436{
437 int start = 0, end = arraylen;
438 int loopbreaker = 0, maxloop = arraylen * 2;
439
440 /* Initialize replace-flag first. */
441 *r_replace = false;
442
443 /* Sneaky optimizations (don't go through searching process if...):
444 * - Keyframe to be added is to be added out of current bounds.
445 * - Keyframe to be added would replace one of the existing ones on bounds.
446 */
447 if (arraylen <= 0 || array == nullptr) {
448 CLOG_WARN(&LOG, "encountered invalid array");
449 return 0;
450 }
451
452 /* Check whether to add before/after/on. */
453 /* 'First' Keyframe (when only one keyframe, this case is used) */
454 float framenum = array[0].vec[1][0];
455 if (IS_EQT(frame, framenum, threshold)) {
456 *r_replace = true;
457 return 0;
458 }
459 if (frame < framenum) {
460 return 0;
461 }
462
463 /* 'Last' Keyframe */
464 framenum = array[(arraylen - 1)].vec[1][0];
465 if (IS_EQT(frame, framenum, threshold)) {
466 *r_replace = true;
467 return (arraylen - 1);
468 }
469 if (frame > framenum) {
470 return arraylen;
471 }
472
473 /* Most of the time, this loop is just to find where to put it
474 * 'loopbreaker' is just here to prevent infinite loops.
475 */
476 for (loopbreaker = 0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
477 /* Compute and get midpoint. */
478
479 /* We calculate the midpoint this way to avoid int overflows... */
480 const int mid = start + ((end - start) / 2);
481
482 const float midfra = array[mid].vec[1][0];
483
484 /* Check if exactly equal to midpoint. */
485 if (IS_EQT(frame, midfra, threshold)) {
486 *r_replace = true;
487 return mid;
488 }
489
490 /* Repeat in upper/lower half. */
491 if (frame > midfra) {
492 start = mid + 1;
493 }
494 else if (frame < midfra) {
495 end = mid - 1;
496 }
497 }
498
499 /* Print error if loop-limit exceeded. */
500 if (loopbreaker == (maxloop - 1)) {
501 CLOG_ERROR(&LOG, "search taking too long");
502
503 /* Include debug info. */
505 "\tround = %d: start = %d, end = %d, arraylen = %d",
506 loopbreaker,
507 start,
508 end,
509 arraylen);
510 }
511
512 /* Not found, so return where to place it. */
513 return start;
514}
515
517 const float frame,
518 const int arraylen,
519 bool *r_replace)
520{
521 /* This is just a wrapper which uses the default threshold. */
523 array, frame, arraylen, BEZT_BINARYSEARCH_THRESH, r_replace);
524}
525
526/* ...................................... */
527
535static bool get_bounding_bezt_indices(const FCurve *fcu,
536 const bool selected_keys_only,
537 const float frame_range[2],
538 int *r_first,
539 int *r_last)
540{
541 /* Sanity checks. */
542 if (fcu->bezt == nullptr) {
543 return false;
544 }
545
546 *r_first = 0;
547 *r_last = fcu->totvert - 1;
548
549 bool found = false;
550 if (frame_range != nullptr) {
551 /* If a range is passed in find the first and last keyframe within that range. */
552 bool replace = false;
554 fcu->bezt, frame_range[0], fcu->totvert, &replace);
556 fcu->bezt, frame_range[1], fcu->totvert, &replace);
557
558 /* If first and last index are the same, no keyframes were found in the range. */
559 if (*r_first == *r_last) {
560 return false;
561 }
562
563 /* The binary search returns an index where a keyframe would be inserted,
564 * so it needs to be clamped to ensure it is in range of the array. */
565 *r_first = clamp_i(*r_first, 0, fcu->totvert - 1);
566 *r_last = clamp_i(*r_last - 1, 0, fcu->totvert - 1);
567 }
568
569 /* Only include selected items? */
570 if (selected_keys_only) {
571 /* Find first selected. */
572 for (int i = *r_first; i <= *r_last; i++) {
573 BezTriple *bezt = &fcu->bezt[i];
574 if (BEZT_ISSEL_ANY(bezt)) {
575 *r_first = i;
576 found = true;
577 break;
578 }
579 }
580
581 /* Find last selected. */
582 for (int i = *r_last; i >= *r_first; i--) {
583 BezTriple *bezt = &fcu->bezt[i];
584 if (BEZT_ISSEL_ANY(bezt)) {
585 *r_last = i;
586 found = true;
587 break;
588 }
589 }
590 }
591 else {
592 found = true;
593 }
594
595 return found;
596}
597
598static void calculate_bezt_bounds_x(BezTriple *bezt_array,
599 const int index_range[2],
600 const bool include_handles,
601 float *r_min,
602 float *r_max)
603{
604 *r_min = bezt_array[index_range[0]].vec[1][0];
605 *r_max = bezt_array[index_range[1]].vec[1][0];
606
607 if (include_handles) {
608 /* Need to check all handles because they might extend beyond their neighboring keys. */
609 for (int i = index_range[0]; i <= index_range[1]; i++) {
610 const BezTriple *bezt = &bezt_array[i];
611 *r_min = min_fff(*r_min, bezt->vec[0][0], bezt->vec[1][0]);
612 *r_max = max_fff(*r_max, bezt->vec[1][0], bezt->vec[2][0]);
613 }
614 }
615}
616
617static void calculate_bezt_bounds_y(BezTriple *bezt_array,
618 const int index_range[2],
619 const bool selected_keys_only,
620 const bool include_handles,
621 float *r_min,
622 float *r_max)
623{
624 *r_min = bezt_array[index_range[0]].vec[1][1];
625 *r_max = bezt_array[index_range[0]].vec[1][1];
626
627 for (int i = index_range[0]; i <= index_range[1]; i++) {
628 const BezTriple *bezt = &bezt_array[i];
629
630 if (selected_keys_only && !BEZT_ISSEL_ANY(bezt)) {
631 continue;
632 }
633
634 *r_min = min_ff(*r_min, bezt->vec[1][1]);
635 *r_max = max_ff(*r_max, bezt->vec[1][1]);
636
637 if (include_handles) {
638 *r_min = min_fff(*r_min, bezt->vec[0][1], bezt->vec[2][1]);
639 *r_max = max_fff(*r_max, bezt->vec[0][1], bezt->vec[2][1]);
640 }
641 }
642}
643
644static bool calculate_bezt_bounds(const FCurve *fcu,
645 const bool selected_keys_only,
646 const bool include_handles,
647 const float frame_range[2],
648 rctf *r_bounds)
649{
650 int index_range[2];
651 const bool found_indices = get_bounding_bezt_indices(
652 fcu, selected_keys_only, frame_range, &index_range[0], &index_range[1]);
653 if (!found_indices) {
654 return false;
655 }
657 fcu->bezt, index_range, include_handles, &r_bounds->xmin, &r_bounds->xmax);
659 index_range,
660 selected_keys_only,
661 include_handles,
662 &r_bounds->ymin,
663 &r_bounds->ymax);
664 return true;
665}
666
667static bool calculate_fpt_bounds(const FCurve *fcu, const float frame_range[2], rctf *r_bounds)
668{
669 r_bounds->xmin = INFINITY;
670 r_bounds->xmax = -INFINITY;
671 r_bounds->ymin = INFINITY;
672 r_bounds->ymax = -INFINITY;
673
674 const int first_index = 0;
675 const int last_index = fcu->totvert - 1;
676 int start_index = first_index;
677 int end_index = last_index;
678
679 if (frame_range != nullptr) {
680 /* Start index can be calculated because fpt has a key on every full frame. */
681 const float start_index_f = frame_range[0] - fcu->fpt[0].vec[0];
682 const float end_index_f = start_index_f + frame_range[1] - frame_range[0];
683
684 if (start_index_f > fcu->totvert - 1 || end_index_f < 0) {
685 /* Range is outside of keyframe samples. */
686 return false;
687 }
688
689 /* Range might be partially covering keyframe samples. */
690 start_index = clamp_i(start_index_f, 0, fcu->totvert - 1);
691 end_index = clamp_i(end_index_f, 0, fcu->totvert - 1);
692 }
693
694 /* X range can be directly calculated from end verts. */
695 r_bounds->xmin = fcu->fpt[start_index].vec[0];
696 r_bounds->xmax = fcu->fpt[end_index].vec[0];
697
698 for (int i = start_index; i <= end_index; i++) {
699 r_bounds->ymin = min_ff(r_bounds->ymin, fcu->fpt[i].vec[1]);
700 r_bounds->ymax = max_ff(r_bounds->ymax, fcu->fpt[i].vec[1]);
701 }
702
703 return BLI_rctf_is_valid(r_bounds);
704}
705
707 const bool selected_keys_only,
708 const bool include_handles,
709 const float frame_range[2],
710 rctf *r_bounds)
711{
712 if (fcu->totvert == 0) {
713 return false;
714 }
715
716 if (fcu->bezt) {
717 const bool found_bounds = calculate_bezt_bounds(
718 fcu, selected_keys_only, include_handles, frame_range, r_bounds);
719 return found_bounds;
720 }
721
722 if (fcu->fpt) {
723 const bool founds_bounds = calculate_fpt_bounds(fcu, frame_range, r_bounds);
724 return founds_bounds;
725 }
726
727 return false;
728}
729
731 float *r_min,
732 float *r_max,
733 const bool selected_keys_only)
734{
735 float min = 0.0f;
736 float max = 0.0f;
737 bool foundvert = false;
738
739 if (fcu->totvert == 0) {
740 return false;
741 }
742
743 if (fcu->bezt) {
744 int index_range[2];
745 foundvert = get_bounding_bezt_indices(
746 fcu, selected_keys_only, nullptr, &index_range[0], &index_range[1]);
747 if (!foundvert) {
748 return false;
749 }
750 const bool include_handles = false;
751 calculate_bezt_bounds_x(fcu->bezt, index_range, include_handles, &min, &max);
752 }
753 else if (fcu->fpt) {
754 min = fcu->fpt[0].vec[0];
755 max = fcu->fpt[fcu->totvert - 1].vec[0];
756
757 foundvert = true;
758 }
759
760 *r_min = min;
761 *r_max = max;
762
763 return foundvert;
764}
765
767 int fcurve_array_len,
768 const float interval,
769 int *r_frames_len)
770{
771 /* Use `1e-3f` as the smallest possible value since these are converted to integers
772 * and we can be sure `MAXFRAME / 1e-3f < INT_MAX` as it's around half the size. */
773 const double interval_db = max_ff(interval, 1e-3f);
774 GSet *frames_unique = BLI_gset_int_new(__func__);
775 for (int fcurve_index = 0; fcurve_index < fcurve_array_len; fcurve_index++) {
776 const FCurve *fcu = fcurve_array[fcurve_index];
777 for (int i = 0; i < fcu->totvert; i++) {
778 const BezTriple *bezt = &fcu->bezt[i];
779 const double value = round(double(bezt->vec[1][0]) / interval_db);
780 BLI_assert(value > INT_MIN && value < INT_MAX);
781 BLI_gset_add(frames_unique, POINTER_FROM_INT(int(value)));
782 }
783 }
784
785 const size_t frames_len = BLI_gset_len(frames_unique);
786 float *frames = static_cast<float *>(MEM_mallocN(sizeof(*frames) * frames_len, __func__));
787
788 GSetIterator gs_iter;
789 int i = 0;
790 GSET_ITER_INDEX (gs_iter, frames_unique, i) {
791 const int value = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
792 frames[i] = double(value) * interval_db;
793 }
794 BLI_gset_free(frames_unique, nullptr);
795
796 qsort(frames, frames_len, sizeof(*frames), BLI_sortutil_cmp_float);
797 *r_frames_len = frames_len;
798 return frames;
799}
800
802 int fcurve_array_len,
803 int *r_frames_len)
804{
805 return BKE_fcurves_calc_keyed_frames_ex(fcurve_array, fcurve_array_len, 1.0f, r_frames_len);
806}
807
810/* -------------------------------------------------------------------- */
814void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt)
815{
816 if (active_bezt == nullptr) {
818 return;
819 }
820
821 /* Gracefully handle out-of-bounds pointers. Ideally this would do a BLI_assert() as well, but
822 * then the unit tests would break in debug mode. */
823 const ptrdiff_t offset = active_bezt - fcu->bezt;
824 if (offset < 0 || offset >= fcu->totvert) {
826 return;
827 }
828
829 /* The active keyframe should always be selected. */
830 BLI_assert_msg(BEZT_ISSEL_ANY(active_bezt), "active keyframe must be selected");
831
832 fcu->active_keyframe_index = int(offset);
833}
834
836{
837 const int active_keyframe_index = fcu->active_keyframe_index;
838
839 /* Array access boundary checks. */
840 if (fcu->bezt == nullptr || active_keyframe_index >= fcu->totvert || active_keyframe_index < 0) {
842 }
843
844 const BezTriple *active_bezt = &fcu->bezt[active_keyframe_index];
845 if (((active_bezt->f1 | active_bezt->f2 | active_bezt->f3) & SELECT) == 0) {
846 /* The active keyframe should always be selected. If it's not selected, it can't be active. */
848 }
849
850 return active_keyframe_index;
851}
852
855void BKE_fcurve_keyframe_move_time_with_handles(BezTriple *keyframe, const float new_time)
856{
857 const float time_delta = new_time - keyframe->vec[1][0];
858 keyframe->vec[0][0] += time_delta;
859 keyframe->vec[1][0] = new_time;
860 keyframe->vec[2][0] += time_delta;
861}
862
863void BKE_fcurve_keyframe_move_value_with_handles(BezTriple *keyframe, const float new_value)
864{
865 const float value_delta = new_value - keyframe->vec[1][1];
866 keyframe->vec[0][1] += value_delta;
867 keyframe->vec[1][1] = new_value;
868 keyframe->vec[2][1] += value_delta;
869}
870
871/* -------------------------------------------------------------------- */
876{
877 /* F-Curve must exist. */
878 if (fcu == nullptr) {
879 return false;
880 }
881
882 /* F-Curve must not have samples - samples are mutually exclusive of keyframes. */
883 if (fcu->fpt) {
884 return false;
885 }
886
887 /* If it has modifiers, none of these should "drastically" alter the curve. */
888 if (fcu->modifiers.first) {
889 /* Check modifiers from last to first, as last will be more influential. */
890 /* TODO: optionally, only check modifier if it is the active one... (Joshua Leung 2010) */
892 /* Ignore if muted/disabled. */
893 if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) {
894 continue;
895 }
896
897 /* Type checks. */
898 switch (fcm->type) {
899 /* Clearly harmless - do nothing. */
903 break;
904
905 /* Sometimes harmful - depending on whether they're "additive" or not. */
907 FMod_Generator *data = (FMod_Generator *)fcm->data;
908
909 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0) {
910 return false;
911 }
912 break;
913 }
916
917 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0) {
918 return false;
919 }
920 break;
921 }
922 /* Always harmful - cannot allow. */
923 default:
924 return false;
925 }
926 }
927 }
928
929 /* Keyframes are usable. */
930 return true;
931}
932
934{
935 return ((fcu->flag & FCURVE_PROTECTED) || (fcu->grp && (fcu->grp->flag & AGRP_PROTECTED)));
936}
937
939{
940 int i;
941 BezTriple *bezt;
942 for (bezt = fcu->bezt, i = 0; i < fcu->totvert; ++i, ++bezt) {
943 if ((bezt->f2 & SELECT) != 0) {
944 return true;
945 }
946 }
947 return false;
948}
949
951{
952 if (!fcu.bezt) {
953 return;
954 }
955 for (int i = 0; i < fcu.totvert; i++) {
956 BEZT_DESEL_ALL(&fcu.bezt[i]);
957 }
958}
959
961{
962 /* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */
963 if (BKE_fcurve_are_keyframes_usable(fcu) == 0) {
964 return false;
965 }
966
967 /* F-Curve must currently be editable too. */
968 if (BKE_fcurve_is_protected(fcu)) {
969 return false;
970 }
971
972 /* F-Curve is keyframable. */
973 return true;
974}
975
978/* -------------------------------------------------------------------- */
982/* Some utilities for working with FPoints (i.e. 'sampled' animation curve data, such as
983 * data imported from BVH/motion-capture files), which are specialized for use with high density
984 * datasets, which BezTriples/Keyframe data are ill equipped to do. */
985
986float fcurve_samplingcb_evalcurve(FCurve *fcu, void * /*data*/, float evaltime)
987{
988 /* Assume any interference from drivers on the curve is intended... */
989 return evaluate_fcurve(fcu, evaltime);
990}
991
992void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb)
993{
994 /* Sanity checks. */
995 /* TODO: make these tests report errors using reports not CLOG's (Joshua Leung 2009) */
996 if (ELEM(nullptr, fcu, sample_cb)) {
997 CLOG_ERROR(&LOG, "No F-Curve with F-Curve Modifiers to Bake");
998 return;
999 }
1000 if (start > end) {
1001 CLOG_ERROR(&LOG, "Error: Frame range for Sampled F-Curve creation is inappropriate");
1002 return;
1003 }
1004
1005 /* Set up sample data. */
1006 FPoint *new_fpt;
1007 FPoint *fpt = new_fpt = static_cast<FPoint *>(
1008 MEM_callocN(sizeof(FPoint) * (end - start + 1), "FPoint Samples"));
1009
1010 /* Use the sampling callback at 1-frame intervals from start to end frames. */
1011 for (int cfra = start; cfra <= end; cfra++, fpt++) {
1012 fpt->vec[0] = float(cfra);
1013 fpt->vec[1] = sample_cb(fcu, data, float(cfra));
1014 }
1015
1016 /* Free any existing sample/keyframe data on curve. */
1017 if (fcu->bezt) {
1018 MEM_freeN(fcu->bezt);
1019 }
1020 if (fcu->fpt) {
1021 MEM_freeN(fcu->fpt);
1022 }
1023
1024 /* Store the samples. */
1025 fcu->bezt = nullptr;
1026 fcu->fpt = new_fpt;
1027 fcu->totvert = end - start + 1;
1028}
1029
1031{
1032 bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
1033 /* Baked FCurve points always use linear interpolation. */
1034 bezt->ipo = BEZT_IPO_LIN;
1035 bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
1036}
1037
1038void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end)
1039{
1040
1041 /* Sanity checks. */
1042 /* TODO: make these tests report errors using reports not CLOG's (Joshua Leung 2009). */
1043 if (fcu == nullptr) {
1044 CLOG_ERROR(&LOG, "No F-Curve with F-Curve Modifiers to Un-Bake");
1045 return;
1046 }
1047
1048 if (start > end) {
1049 CLOG_ERROR(&LOG, "Error: Frame range to unbake F-Curve is inappropriate");
1050 return;
1051 }
1052
1053 if (fcu->fpt == nullptr) {
1054 /* No data to unbake. */
1055 CLOG_ERROR(&LOG, "Error: Curve contains no baked keyframes");
1056 return;
1057 }
1058
1059 /* Free any existing sample/keyframe data on the curve. */
1060 if (fcu->bezt) {
1061 MEM_freeN(fcu->bezt);
1062 }
1063
1064 FPoint *fpt = fcu->fpt;
1065 int keyframes_to_insert = end - start;
1066 int sample_points = fcu->totvert;
1067
1068 BezTriple *bezt = fcu->bezt = static_cast<BezTriple *>(
1069 MEM_callocN(sizeof(*fcu->bezt) * size_t(keyframes_to_insert), __func__));
1070 fcu->totvert = keyframes_to_insert;
1071
1072 /* Get first sample point to 'copy' as keyframe. */
1073 for (; sample_points && (fpt->vec[0] < start); fpt++, sample_points--) {
1074 /* pass */
1075 }
1076
1077 /* Current position in the timeline. */
1078 int cur_pos = start;
1079
1080 /* Add leading dummy flat points if needed. */
1081 for (; keyframes_to_insert && (fpt->vec[0] > start); cur_pos++, bezt++, keyframes_to_insert--) {
1083 bezt->vec[1][0] = float(cur_pos);
1084 bezt->vec[1][1] = fpt->vec[1];
1085 }
1086
1087 /* Copy actual sample points. */
1088 for (; keyframes_to_insert && sample_points;
1089 cur_pos++, bezt++, keyframes_to_insert--, fpt++, sample_points--)
1090 {
1092 copy_v2_v2(bezt->vec[1], fpt->vec);
1093 }
1094
1095 /* Add trailing dummy flat points if needed. */
1096 for (fpt--; keyframes_to_insert; cur_pos++, bezt++, keyframes_to_insert--) {
1098 bezt->vec[1][0] = float(cur_pos);
1099 bezt->vec[1][1] = fpt->vec[1];
1100 }
1101
1102 MEM_SAFE_FREE(fcu->fpt);
1103
1104 /* Not strictly needed since we use linear interpolation, but better be consistent here. */
1106}
1107
1108/* ***************************** F-Curve Sanity ********************************* */
1109/* The functions here are used in various parts of Blender, usually after some editing
1110 * of keyframe data has occurred. They ensure that keyframe data is properly ordered and
1111 * that the handles are correct.
1112 */
1113
1115{
1116 FModifier *fcm = static_cast<FModifier *>(fcu->modifiers.first);
1117
1118 if (!fcm || fcm->type != FMODIFIER_TYPE_CYCLES) {
1119 return FCU_CYCLE_NONE;
1120 }
1121
1123 return FCU_CYCLE_NONE;
1124 }
1125
1127 return FCU_CYCLE_NONE;
1128 }
1129
1130 FMod_Cycles *data = (FMod_Cycles *)fcm->data;
1131
1132 if (data && data->after_cycles == 0 && data->before_cycles == 0) {
1133 if (data->before_mode == FCM_EXTRAPOLATE_CYCLIC && data->after_mode == FCM_EXTRAPOLATE_CYCLIC)
1134 {
1135 return FCU_CYCLE_PERFECT;
1136 }
1137
1140 {
1141 return FCU_CYCLE_OFFSET;
1142 }
1143 }
1144
1145 return FCU_CYCLE_NONE;
1146}
1147
1149{
1151}
1152
1153/* Shifts 'in' by the difference in coordinates between 'to' and 'from',
1154 * using 'out' as the output buffer.
1155 * When 'to' and 'from' are end points of the loop, this moves the 'in' point one loop cycle.
1156 */
1158 bool cycle, BezTriple *out, const BezTriple *in, const BezTriple *from, const BezTriple *to)
1159{
1160 if (!cycle) {
1161 return nullptr;
1162 }
1163
1164 memcpy(out, in, sizeof(BezTriple));
1165
1166 float delta[3];
1167 sub_v3_v3v3(delta, to->vec[1], from->vec[1]);
1168
1169 for (int i = 0; i < 3; i++) {
1170 add_v3_v3(out->vec[i], delta);
1171 }
1172
1173 return out;
1174}
1175
1177{
1178 using namespace blender;
1179 /* Error checking:
1180 * - Need at least two points.
1181 * - Need bezier keys.
1182 * - Only bezier-interpolation has handles (for now).
1183 */
1184 if (ELEM(nullptr, fcu, fcu->bezt) ||
1185 (fcu->totvert < 2) /*|| ELEM(fcu->ipo, BEZT_IPO_CONST, BEZT_IPO_LIN) */)
1186 {
1187 return;
1188 }
1189
1190 /* If the first modifier is Cycles, smooth the curve through the cycle. */
1191 BezTriple *first = &fcu->bezt[0];
1192 BezTriple *last = &fcu->bezt[fcu->totvert - 1];
1193 const bool cycle = BKE_fcurve_is_cyclic(fcu) && BEZT_IS_AUTOH(first) && BEZT_IS_AUTOH(last);
1194
1195 threading::parallel_for(IndexRange(fcu->totvert), 256, [&](const IndexRange range) {
1196 BezTriple tmp;
1197 for (const int i : range) {
1198 BezTriple *bezt = &fcu->bezt[i];
1199 BezTriple *prev = nullptr;
1200 BezTriple *next = nullptr;
1201 if (i > 0) {
1202 prev = (bezt - 1);
1203 }
1204 else {
1205 prev = cycle_offset_triple(cycle, &tmp, &fcu->bezt[fcu->totvert - 2], last, first);
1206 }
1207 if (i < fcu->totvert - 1) {
1208 next = (bezt + 1);
1209 }
1210 else {
1211 next = cycle_offset_triple(cycle, &tmp, &fcu->bezt[1], first, last);
1212 }
1213
1214 /* Clamp timing of handles to be on either side of beztriple. */
1215 CLAMP_MAX(bezt->vec[0][0], bezt->vec[1][0]);
1216 CLAMP_MIN(bezt->vec[2][0], bezt->vec[1][0]);
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
1359/* -------------------------------------------------------------------- */
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_shrink(FCurve *fcu, const int new_totvert)
1616{
1617 BLI_assert(new_totvert >= 0);
1618 BLI_assert(new_totvert <= fcu->totvert);
1619
1620 /* No early return when new_totvert == fcu->totvert. There is no way to know the intention of the
1621 * caller, nor the history of the FCurve so far, so `fcu->bezt` may actually have allocated space
1622 * for more than `fcu->totvert` keys. */
1623
1624 if (new_totvert == 0) {
1625 fcurve_bezt_free(fcu);
1626 return;
1627 }
1628
1629 fcu->bezt = static_cast<BezTriple *>(
1630 MEM_reallocN(fcu->bezt, new_totvert * sizeof(*(fcu->bezt))));
1631 fcu->totvert = new_totvert;
1632}
1633
1634void BKE_fcurve_delete_key(FCurve *fcu, int index)
1635{
1636 /* sanity check */
1637 if (fcu == nullptr) {
1638 return;
1639 }
1640
1641 /* verify the index:
1642 * 1) cannot be greater than the number of available keyframes
1643 * 2) negative indices are for specifying a value from the end of the array
1644 */
1645 if (abs(index) >= fcu->totvert) {
1646 return;
1647 }
1648 if (index < 0) {
1649 index += fcu->totvert;
1650 }
1651
1652 /* Delete this keyframe */
1653 memmove(
1654 &fcu->bezt[index], &fcu->bezt[index + 1], sizeof(BezTriple) * (fcu->totvert - index - 1));
1655 fcu->totvert--;
1656
1657 /* Free the array of BezTriples if there are not keyframes */
1658 if (fcu->totvert == 0) {
1659 fcurve_bezt_free(fcu);
1660 }
1661}
1662
1664{
1665 BLI_assert(fcu != nullptr);
1666 BLI_assert(fcu->bezt != nullptr);
1667 BLI_assert(index_range[1] > index_range[0]);
1668 BLI_assert(index_range[1] <= fcu->totvert);
1669
1670 const int removed_index_count = index_range[1] - index_range[0];
1671 memmove(&fcu->bezt[index_range[0]],
1672 &fcu->bezt[index_range[1]],
1673 sizeof(BezTriple) * (fcu->totvert - index_range[1]));
1674 fcu->totvert -= removed_index_count;
1675
1676 if (fcu->totvert == 0) {
1677 fcurve_bezt_free(fcu);
1678 }
1679}
1680
1682 const BezTriple *a, const int size_a, const BezTriple *b, const int size_b, int *r_merged_size)
1683{
1684 BezTriple *large_array = static_cast<BezTriple *>(
1685 MEM_callocN((size_a + size_b) * sizeof(BezTriple), "beztriple"));
1686
1687 int iterator_a = 0;
1688 int iterator_b = 0;
1689 *r_merged_size = 0;
1690
1691 /* For comparing if keyframes are at the same x-value. */
1692 const int max_ulps = 32;
1693
1694 while (iterator_a < size_a || iterator_b < size_b) {
1695 if (iterator_a >= size_a) {
1696 const int remaining_keys = size_b - iterator_b;
1697 memcpy(&large_array[*r_merged_size], &b[iterator_b], sizeof(BezTriple) * remaining_keys);
1698 (*r_merged_size) += remaining_keys;
1699 break;
1700 }
1701 if (iterator_b >= size_b) {
1702 const int remaining_keys = size_a - iterator_a;
1703 memcpy(&large_array[*r_merged_size], &a[iterator_a], sizeof(BezTriple) * remaining_keys);
1704 (*r_merged_size) += remaining_keys;
1705 break;
1706 }
1707
1709 a[iterator_a].vec[1][0], b[iterator_b].vec[1][0], BEZT_BINARYSEARCH_THRESH, max_ulps))
1710 {
1711 memcpy(&large_array[*r_merged_size], &a[iterator_a], sizeof(BezTriple));
1712 iterator_a++;
1713 iterator_b++;
1714 }
1715 else if (a[iterator_a].vec[1][0] < b[iterator_b].vec[1][0]) {
1716 memcpy(&large_array[*r_merged_size], &a[iterator_a], sizeof(BezTriple));
1717 iterator_a++;
1718 }
1719 else {
1720 memcpy(&large_array[*r_merged_size], &b[iterator_b], sizeof(BezTriple));
1721 iterator_b++;
1722 }
1723 (*r_merged_size)++;
1724 }
1725
1726 BezTriple *minimal_array;
1727 if (*r_merged_size < size_a + size_b) {
1728 minimal_array = static_cast<BezTriple *>(
1729 MEM_reallocN(large_array, sizeof(BezTriple) * (*r_merged_size)));
1730 }
1731 else {
1732 minimal_array = large_array;
1733 }
1734
1735 return minimal_array;
1736}
1737
1739{
1740 if (fcu->bezt == nullptr) { /* ignore baked curves */
1741 return false;
1742 }
1743
1744 bool changed = false;
1745
1746 /* Delete selected BezTriples */
1747 for (int i = 0; i < fcu->totvert; i++) {
1748 if (fcu->bezt[i].f2 & SELECT) {
1749 if (i == fcu->active_keyframe_index) {
1750 BKE_fcurve_active_keyframe_set(fcu, nullptr);
1751 }
1752 memmove(&fcu->bezt[i], &fcu->bezt[i + 1], sizeof(BezTriple) * (fcu->totvert - i - 1));
1753 fcu->totvert--;
1754 i--;
1755 changed = true;
1756 }
1757 }
1758
1759 /* Free the array of BezTriples if there are not keyframes */
1760 if (fcu->totvert == 0) {
1761 fcurve_bezt_free(fcu);
1762 }
1763
1764 return changed;
1765}
1766
1768{
1769 fcurve_bezt_free(fcu);
1770}
1771
1772/* Time + Average value */
1775 float frame; /* frame to cluster around */
1776 float val; /* average value */
1777
1778 size_t tot_count; /* number of keyframes that have been averaged */
1779 size_t del_count; /* number of keyframes of this sort that have been deleted so far */
1780};
1781
1782void BKE_fcurve_merge_duplicate_keys(FCurve *fcu, const int sel_flag, const bool use_handle)
1783{
1784 /* NOTE: We assume that all keys are sorted */
1785 ListBase retained_keys = {nullptr, nullptr};
1786 const bool can_average_points = ((fcu->flag & (FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES)) ==
1787 0);
1788
1789 /* sanity checks */
1790 if ((fcu->totvert == 0) || (fcu->bezt == nullptr)) {
1791 return;
1792 }
1793
1794 /* 1) Identify selected keyframes, and average the values on those
1795 * in case there are collisions due to multiple keys getting scaled
1796 * to all end up on the same frame
1797 */
1798 for (int i = 0; i < fcu->totvert; i++) {
1799 BezTriple *bezt = &fcu->bezt[i];
1800
1801 if (BEZT_ISSEL_ANY(bezt)) {
1802 bool found = false;
1803
1804 /* If there's another selected frame here, merge it */
1805 LISTBASE_FOREACH_BACKWARD (tRetainedKeyframe *, rk, &retained_keys) {
1806 if (IS_EQT(rk->frame, bezt->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
1807 rk->val += bezt->vec[1][1];
1808 rk->tot_count++;
1809
1810 found = true;
1811 break;
1812 }
1813 if (rk->frame < bezt->vec[1][0]) {
1814 /* Terminate early if have passed the supposed insertion point? */
1815 break;
1816 }
1817 }
1818
1819 /* If nothing found yet, create a new one */
1820 if (found == false) {
1821 tRetainedKeyframe *rk = static_cast<tRetainedKeyframe *>(
1822 MEM_callocN(sizeof(tRetainedKeyframe), "tRetainedKeyframe"));
1823
1824 rk->frame = bezt->vec[1][0];
1825 rk->val = bezt->vec[1][1];
1826 rk->tot_count = 1;
1827
1828 BLI_addtail(&retained_keys, rk);
1829 }
1830 }
1831 }
1832
1833 if (BLI_listbase_is_empty(&retained_keys)) {
1834 /* This may happen if none of the points were selected... */
1835 if (G.debug & G_DEBUG) {
1836 printf("%s: nothing to do for FCurve %p (rna_path = '%s')\n", __func__, fcu, fcu->rna_path);
1837 }
1838 return;
1839 }
1840
1841 /* Compute the average values for each retained keyframe */
1842 LISTBASE_FOREACH (tRetainedKeyframe *, rk, &retained_keys) {
1843 rk->val = rk->val / float(rk->tot_count);
1844 }
1845
1846 /* 2) Delete all keyframes duplicating the "retained keys" found above
1847 * - Most of these will be unselected keyframes
1848 * - Some will be selected keyframes though. For those, we only keep the last one
1849 * (or else everything is gone), and replace its value with the averaged value.
1850 */
1851 for (int i = fcu->totvert - 1; i >= 0; i--) {
1852 BezTriple *bezt = &fcu->bezt[i];
1853
1854 /* Is this keyframe a candidate for deletion? */
1855 /* TODO: Replace loop with an O(1) lookup instead */
1856 LISTBASE_FOREACH_BACKWARD (tRetainedKeyframe *, rk, &retained_keys) {
1857 if (IS_EQT(bezt->vec[1][0], rk->frame, BEZT_BINARYSEARCH_THRESH)) {
1858 /* Selected keys are treated with greater care than unselected ones... */
1859 if (BEZT_ISSEL_ANY(bezt)) {
1860 /* - If this is the last selected key left (based on rk->del_count) ==> UPDATE IT
1861 * (or else we wouldn't have any keyframe left here)
1862 * - Otherwise, there are still other selected keyframes on this frame
1863 * to be merged down still ==> DELETE IT
1864 */
1865 if (rk->del_count == rk->tot_count - 1) {
1866 /* Update keyframe... */
1867 if (can_average_points) {
1868 /* TODO: update handles too? */
1869 bezt->vec[1][1] = rk->val;
1870 }
1871 }
1872 else {
1873 /* Delete Keyframe */
1874 BKE_fcurve_delete_key(fcu, i);
1875 }
1876
1877 /* Update count of how many we've deleted
1878 * - It should only matter that we're doing this for all but the last one
1879 */
1880 rk->del_count++;
1881 }
1882 else {
1883 /* Always delete - Unselected keys don't matter */
1884 BKE_fcurve_delete_key(fcu, i);
1885 }
1886
1887 /* Stop the RK search... we've found our match now */
1888 break;
1889 }
1890 }
1891 }
1892
1893 /* 3) Recalculate handles */
1894 testhandles_fcurve(fcu, eBezTriple_Flag(sel_flag), use_handle);
1895
1896 /* cleanup */
1897 BLI_freelistN(&retained_keys);
1898}
1899
1901{
1902 if (fcu->totvert < 2) {
1903 return;
1904 }
1905
1906 BLI_assert_msg(fcu->bezt, "this function only works with regular (non-sampled) FCurves");
1907 if (fcu->bezt == nullptr) {
1908 return;
1909 }
1910
1911 int prev_bezt_index = 0;
1912 for (int i = 1; i < fcu->totvert; i++) {
1913 BezTriple *bezt = &fcu->bezt[i];
1914 BezTriple *prev_bezt = &fcu->bezt[prev_bezt_index];
1915
1916 const float bezt_x = bezt->vec[1][0];
1917 const float prev_x = prev_bezt->vec[1][0];
1918
1919 if (bezt_x - prev_x <= BEZT_BINARYSEARCH_THRESH) {
1920 /* Replace 'prev_bezt', as it has the same X-coord as 'bezt' and the last one wins. */
1921 *prev_bezt = *bezt;
1922
1923 if (floor(bezt_x) == bezt_x) {
1924 /* Keep the 'bezt_x' coordinate, as being on a frame is more desirable
1925 * than being ever so slightly off. */
1926 }
1927 else {
1928 /* Move the retained key to the old X-coordinate, to 'anchor' the X-coordinate used for
1929 * subsequent comparisons. Without this, the reference X-coordinate would keep moving
1930 * forward in time, potentially merging in more keys than desired. */
1932 }
1933 continue;
1934 }
1935
1936 /* Next iteration should look at the current element. However, because of the deletions, that
1937 * may not be at index 'i'; after this increment, `prev_bezt_index` points at where the current
1938 * element should go. */
1939 prev_bezt_index++;
1940
1941 if (prev_bezt_index != i) {
1942 /* This bezt should be kept, so copy it to its new location in the array. */
1943 fcu->bezt[prev_bezt_index] = *bezt;
1944 }
1945 }
1946
1947 BKE_fcurve_bezt_shrink(fcu, prev_bezt_index + 1);
1948}
1949
1952/* -------------------------------------------------------------------- */
1957 const BezTriple *bezts,
1958 float evaltime,
1959 int endpoint_offset,
1960 int direction_to_neighbor)
1961{
1962 /* The first/last keyframe. */
1963 const BezTriple *endpoint_bezt = bezts + endpoint_offset;
1964 /* The second (to last) keyframe. */
1965 const BezTriple *neighbor_bezt = endpoint_bezt + direction_to_neighbor;
1966
1967 if (endpoint_bezt->ipo == BEZT_IPO_CONST || fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT ||
1968 (fcu->flag & FCURVE_DISCRETE_VALUES) != 0)
1969 {
1970 /* Constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, so just extend the
1971 * endpoint's value. */
1972 return endpoint_bezt->vec[1][1];
1973 }
1974
1975 if (endpoint_bezt->ipo == BEZT_IPO_LIN) {
1976 /* Use the next center point instead of our own handle for linear interpolated extrapolate. */
1977 if (fcu->totvert == 1) {
1978 return endpoint_bezt->vec[1][1];
1979 }
1980
1981 const float dx = endpoint_bezt->vec[1][0] - evaltime;
1982 float fac = neighbor_bezt->vec[1][0] - endpoint_bezt->vec[1][0];
1983
1984 /* Prevent division by zero. */
1985 if (fac == 0.0f) {
1986 return endpoint_bezt->vec[1][1];
1987 }
1988
1989 fac = (neighbor_bezt->vec[1][1] - endpoint_bezt->vec[1][1]) / fac;
1990 return endpoint_bezt->vec[1][1] - (fac * dx);
1991 }
1992
1993 /* Use the gradient of the second handle (later) of neighbor to calculate the gradient and thus
1994 * the value of the curve at evaluation time. */
1995 const int handle = direction_to_neighbor > 0 ? 0 : 2;
1996 const float dx = endpoint_bezt->vec[1][0] - evaltime;
1997 float fac = endpoint_bezt->vec[1][0] - endpoint_bezt->vec[handle][0];
1998
1999 /* Prevent division by zero. */
2000 if (fac == 0.0f) {
2001 return endpoint_bezt->vec[1][1];
2002 }
2003
2004 fac = (endpoint_bezt->vec[1][1] - endpoint_bezt->vec[handle][1]) / fac;
2005 return endpoint_bezt->vec[1][1] - (fac * dx);
2006}
2007
2009 const BezTriple *bezts,
2010 float evaltime)
2011{
2012 const float eps = 1.e-8f;
2013 uint a;
2014
2015 /* Evaluation-time occurs somewhere in the middle of the curve. */
2016 bool exact = false;
2017
2018 /* Use binary search to find appropriate keyframes...
2019 *
2020 * The threshold here has the following constraints:
2021 * - 0.001 is too coarse:
2022 * We get artifacts with 2cm driver movements at 1BU = 1m (see #40332).
2023 *
2024 * - 0.00001 is too fine:
2025 * Weird errors, like selecting the wrong keyframe range (see #39207), occur.
2026 * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd.
2027 */
2028 a = BKE_fcurve_bezt_binarysearch_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact);
2029 const BezTriple *bezt = bezts + a;
2030
2031 if (exact) {
2032 /* Index returned must be interpreted differently when it sits on top of an existing keyframe
2033 * - That keyframe is the start of the segment we need (see action_bug_2.blend in #39207).
2034 */
2035 return bezt->vec[1][1];
2036 }
2037
2038 /* Index returned refers to the keyframe that the eval-time occurs *before*
2039 * - hence, that keyframe marks the start of the segment we're dealing with.
2040 */
2041 const BezTriple *prevbezt = (a > 0) ? (bezt - 1) : bezt;
2042
2043 /* Use if the key is directly on the frame, in rare cases this is needed else we get 0.0 instead.
2044 * XXX: consult #39207 for examples of files where failure of these checks can cause issues. */
2045 if (fabsf(bezt->vec[1][0] - evaltime) < eps) {
2046 return bezt->vec[1][1];
2047 }
2048
2049 if (evaltime < prevbezt->vec[1][0] || bezt->vec[1][0] < evaltime) {
2050 if (G.debug & G_DEBUG) {
2051 printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n",
2052 prevbezt->vec[1][0],
2053 bezt->vec[1][0],
2054 evaltime,
2055 fabsf(bezt->vec[1][0] - evaltime));
2056 }
2057 return 0.0f;
2058 }
2059
2060 /* Evaluation-time occurs within the interval defined by these two keyframes. */
2061 const float begin = prevbezt->vec[1][1];
2062 const float change = bezt->vec[1][1] - prevbezt->vec[1][1];
2063 const float duration = bezt->vec[1][0] - prevbezt->vec[1][0];
2064 const float time = evaltime - prevbezt->vec[1][0];
2065 const float amplitude = prevbezt->amplitude;
2066 const float period = prevbezt->period;
2067
2068 /* Value depends on interpolation mode. */
2069 if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) || (duration == 0))
2070 {
2071 /* Constant (evaltime not relevant, so no interpolation needed). */
2072 return prevbezt->vec[1][1];
2073 }
2074
2075 switch (prevbezt->ipo) {
2076 /* Interpolation ...................................... */
2077 case BEZT_IPO_BEZ: {
2078 float v1[2], v2[2], v3[2], v4[2], opl[32];
2079
2080 /* Bezier interpolation. */
2081 /* (v1, v2) are the first keyframe and its 2nd handle. */
2082 v1[0] = prevbezt->vec[1][0];
2083 v1[1] = prevbezt->vec[1][1];
2084 v2[0] = prevbezt->vec[2][0];
2085 v2[1] = prevbezt->vec[2][1];
2086 /* (v3, v4) are the last keyframe's 1st handle + the last keyframe. */
2087 v3[0] = bezt->vec[0][0];
2088 v3[1] = bezt->vec[0][1];
2089 v4[0] = bezt->vec[1][0];
2090 v4[1] = bezt->vec[1][1];
2091
2092 if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON &&
2093 fabsf(v3[1] - v4[1]) < FLT_EPSILON)
2094 {
2095 /* Optimization: If all the handles are flat/at the same values,
2096 * the value is simply the shared value (see #40372 -> F91346).
2097 */
2098 return v1[1];
2099 }
2100 /* Adjust handles so that they don't overlap (forming a loop). */
2101 BKE_fcurve_correct_bezpart(v1, v2, v3, v4);
2102
2103 /* Try to get a value for this position - if failure, try another set of points. */
2104 if (!findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl)) {
2105 if (G.debug & G_DEBUG) {
2106 printf(" ERROR: findzero() failed at %f with %f %f %f %f\n",
2107 evaltime,
2108 v1[0],
2109 v2[0],
2110 v3[0],
2111 v4[0]);
2112 }
2113 return 0.0;
2114 }
2115
2116 berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1);
2117 return opl[0];
2118 }
2119 case BEZT_IPO_LIN:
2120 /* Linear - simply linearly interpolate between values of the two keyframes. */
2121 return BLI_easing_linear_ease(time, begin, change, duration);
2122
2123 /* Easing ............................................ */
2124 case BEZT_IPO_BACK:
2125 switch (prevbezt->easing) {
2126 case BEZT_IPO_EASE_IN:
2127 return BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back);
2128 case BEZT_IPO_EASE_OUT:
2129 return BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
2131 return BLI_easing_back_ease_in_out(time, begin, change, duration, prevbezt->back);
2132
2133 default: /* Default/Auto: same as ease out. */
2134 return BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
2135 }
2136 break;
2137
2138 case BEZT_IPO_BOUNCE:
2139 switch (prevbezt->easing) {
2140 case BEZT_IPO_EASE_IN:
2141 return BLI_easing_bounce_ease_in(time, begin, change, duration);
2142 case BEZT_IPO_EASE_OUT:
2143 return BLI_easing_bounce_ease_out(time, begin, change, duration);
2145 return BLI_easing_bounce_ease_in_out(time, begin, change, duration);
2146
2147 default: /* Default/Auto: same as ease out. */
2148 return BLI_easing_bounce_ease_out(time, begin, change, duration);
2149 }
2150 break;
2151
2152 case BEZT_IPO_CIRC:
2153 switch (prevbezt->easing) {
2154 case BEZT_IPO_EASE_IN:
2155 return BLI_easing_circ_ease_in(time, begin, change, duration);
2156 case BEZT_IPO_EASE_OUT:
2157 return BLI_easing_circ_ease_out(time, begin, change, duration);
2159 return BLI_easing_circ_ease_in_out(time, begin, change, duration);
2160
2161 default: /* Default/Auto: same as ease in. */
2162 return BLI_easing_circ_ease_in(time, begin, change, duration);
2163 }
2164 break;
2165
2166 case BEZT_IPO_CUBIC:
2167 switch (prevbezt->easing) {
2168 case BEZT_IPO_EASE_IN:
2169 return BLI_easing_cubic_ease_in(time, begin, change, duration);
2170 case BEZT_IPO_EASE_OUT:
2171 return BLI_easing_cubic_ease_out(time, begin, change, duration);
2173 return BLI_easing_cubic_ease_in_out(time, begin, change, duration);
2174
2175 default: /* Default/Auto: same as ease in. */
2176 return BLI_easing_cubic_ease_in(time, begin, change, duration);
2177 }
2178 break;
2179
2180 case BEZT_IPO_ELASTIC:
2181 switch (prevbezt->easing) {
2182 case BEZT_IPO_EASE_IN:
2183 return BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period);
2184 case BEZT_IPO_EASE_OUT:
2185 return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
2187 return BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period);
2188
2189 default: /* Default/Auto: same as ease out. */
2190 return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
2191 }
2192 break;
2193
2194 case BEZT_IPO_EXPO:
2195 switch (prevbezt->easing) {
2196 case BEZT_IPO_EASE_IN:
2197 return BLI_easing_expo_ease_in(time, begin, change, duration);
2198 case BEZT_IPO_EASE_OUT:
2199 return BLI_easing_expo_ease_out(time, begin, change, duration);
2201 return BLI_easing_expo_ease_in_out(time, begin, change, duration);
2202
2203 default: /* Default/Auto: same as ease in. */
2204 return BLI_easing_expo_ease_in(time, begin, change, duration);
2205 }
2206 break;
2207
2208 case BEZT_IPO_QUAD:
2209 switch (prevbezt->easing) {
2210 case BEZT_IPO_EASE_IN:
2211 return BLI_easing_quad_ease_in(time, begin, change, duration);
2212 case BEZT_IPO_EASE_OUT:
2213 return BLI_easing_quad_ease_out(time, begin, change, duration);
2215 return BLI_easing_quad_ease_in_out(time, begin, change, duration);
2216
2217 default: /* Default/Auto: same as ease in. */
2218 return BLI_easing_quad_ease_in(time, begin, change, duration);
2219 }
2220 break;
2221
2222 case BEZT_IPO_QUART:
2223 switch (prevbezt->easing) {
2224 case BEZT_IPO_EASE_IN:
2225 return BLI_easing_quart_ease_in(time, begin, change, duration);
2226 case BEZT_IPO_EASE_OUT:
2227 return BLI_easing_quart_ease_out(time, begin, change, duration);
2229 return BLI_easing_quart_ease_in_out(time, begin, change, duration);
2230
2231 default: /* Default/Auto: same as ease in. */
2232 return BLI_easing_quart_ease_in(time, begin, change, duration);
2233 }
2234 break;
2235
2236 case BEZT_IPO_QUINT:
2237 switch (prevbezt->easing) {
2238 case BEZT_IPO_EASE_IN:
2239 return BLI_easing_quint_ease_in(time, begin, change, duration);
2240 case BEZT_IPO_EASE_OUT:
2241 return BLI_easing_quint_ease_out(time, begin, change, duration);
2243 return BLI_easing_quint_ease_in_out(time, begin, change, duration);
2244
2245 default: /* Default/Auto: same as ease in. */
2246 return BLI_easing_quint_ease_in(time, begin, change, duration);
2247 }
2248 break;
2249
2250 case BEZT_IPO_SINE:
2251 switch (prevbezt->easing) {
2252 case BEZT_IPO_EASE_IN:
2253 return BLI_easing_sine_ease_in(time, begin, change, duration);
2254 case BEZT_IPO_EASE_OUT:
2255 return BLI_easing_sine_ease_out(time, begin, change, duration);
2257 return BLI_easing_sine_ease_in_out(time, begin, change, duration);
2258
2259 default: /* Default/Auto: same as ease in. */
2260 return BLI_easing_sine_ease_in(time, begin, change, duration);
2261 }
2262 break;
2263
2264 default:
2265 return prevbezt->vec[1][1];
2266 }
2267
2268 return 0.0f;
2269}
2270
2271/* Calculate F-Curve value for 'evaltime' using #BezTriple keyframes. */
2272static float fcurve_eval_keyframes(const FCurve *fcu, const BezTriple *bezts, float evaltime)
2273{
2274 if (evaltime <= bezts->vec[1][0]) {
2275 return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, 0, +1);
2276 }
2277
2278 const BezTriple *lastbezt = bezts + fcu->totvert - 1;
2279 if (lastbezt->vec[1][0] <= evaltime) {
2280 return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, fcu->totvert - 1, -1);
2281 }
2282
2283 return fcurve_eval_keyframes_interpolate(fcu, bezts, evaltime);
2284}
2285
2286/* Calculate F-Curve value for 'evaltime' using #FPoint samples. */
2287static float fcurve_eval_samples(const FCurve *fcu, const FPoint *fpts, float evaltime)
2288{
2289 float cvalue = 0.0f;
2290
2291 /* Get pointers. */
2292 const FPoint *prevfpt = fpts;
2293 const FPoint *lastfpt = prevfpt + fcu->totvert - 1;
2294
2295 /* Evaluation time at or past endpoints? */
2296 if (prevfpt->vec[0] >= evaltime) {
2297 /* Before or on first sample, so just extend value. */
2298 cvalue = prevfpt->vec[1];
2299 }
2300 else if (lastfpt->vec[0] <= evaltime) {
2301 /* After or on last sample, so just extend value. */
2302 cvalue = lastfpt->vec[1];
2303 }
2304 else {
2305 float t = fabsf(evaltime - floorf(evaltime));
2306
2307 /* Find the one on the right frame (assume that these are spaced on 1-frame intervals). */
2308 const FPoint *fpt = prevfpt + (int(evaltime) - int(prevfpt->vec[0]));
2309
2310 /* If not exactly on the frame, perform linear interpolation with the next one. */
2311 if (t != 0.0f && t < 1.0f) {
2312 cvalue = interpf(fpt->vec[1], (fpt + 1)->vec[1], 1.0f - t);
2313 }
2314 else {
2315 cvalue = fpt->vec[1];
2316 }
2317 }
2318
2319 return cvalue;
2320}
2321
2324/* -------------------------------------------------------------------- */
2328/* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime")
2329 * NOTE: this is also used for drivers.
2330 */
2331static float evaluate_fcurve_ex(const FCurve *fcu, float evaltime, float cvalue)
2332{
2333 /* Evaluate modifiers which modify time to evaluate the base curve at. */
2334 FModifiersStackStorage storage;
2337 storage.buffer = alloca(storage.modifier_count * storage.size_per_modifier);
2338
2339 const float devaltime = evaluate_time_fmodifiers(
2340 &storage, &fcu->modifiers, fcu, cvalue, evaltime);
2341
2342 /* Evaluate curve-data
2343 * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying
2344 * F-Curve modifier on the stack requested the curve to be evaluated at.
2345 */
2346 if (fcu->bezt) {
2347 cvalue = fcurve_eval_keyframes(fcu, fcu->bezt, devaltime);
2348 }
2349 else if (fcu->fpt) {
2350 cvalue = fcurve_eval_samples(fcu, fcu->fpt, devaltime);
2351 }
2352
2353 /* Evaluate modifiers. */
2354 evaluate_value_fmodifiers(&storage, &fcu->modifiers, fcu, &cvalue, devaltime);
2355
2356 /* If curve can only have integral values, perform truncation (i.e. drop the decimal part)
2357 * here so that the curve can be sampled correctly.
2358 */
2359 if (fcu->flag & FCURVE_INT_VALUES) {
2360 cvalue = floorf(cvalue + 0.5f);
2361 }
2362
2363 return cvalue;
2364}
2365
2366float evaluate_fcurve(const FCurve *fcu, float evaltime)
2367{
2368 BLI_assert(fcu->driver == nullptr);
2369
2370 return evaluate_fcurve_ex(fcu, evaltime, 0.0);
2371}
2372
2374{
2375 /* Can be used to evaluate the (key-framed) f-curve only.
2376 * Also works for driver-f-curves when the driver itself is not relevant.
2377 * E.g. when inserting a keyframe in a driver f-curve. */
2378 return evaluate_fcurve_ex(fcu, evaltime, 0.0);
2379}
2380
2382 FCurve *fcu,
2383 ChannelDriver *driver_orig,
2384 const AnimationEvalContext *anim_eval_context)
2385{
2386 BLI_assert(fcu->driver != nullptr);
2387 float cvalue = 0.0f;
2388 float evaltime = anim_eval_context->eval_time;
2389
2390 /* If there is a driver (only if this F-Curve is acting as 'driver'),
2391 * evaluate it to find value to use as `evaltime` since drivers essentially act as alternative
2392 * input (i.e. in place of 'time') for F-Curves. */
2393 if (fcu->driver) {
2394 /* Evaluation-time now serves as input for the curve. */
2395 evaltime = evaluate_driver(anim_rna, fcu->driver, driver_orig, anim_eval_context);
2396
2397 /* Only do a default 1-1 mapping if it's unlikely that anything else will set a value... */
2398 if (fcu->totvert == 0) {
2399 bool do_linear = true;
2400
2401 /* Out-of-range F-Modifiers will block, as will those which just plain overwrite the values
2402 * XXX: additive is a bit more dicey; it really depends then if things are in range or not...
2403 */
2404 LISTBASE_FOREACH (FModifier *, fcm, &fcu->modifiers) {
2405 /* If there are range-restrictions, we must definitely block #36950. */
2406 if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 ||
2407 (fcm->sfra <= evaltime && fcm->efra >= evaltime))
2408 {
2409 /* Within range: here it probably doesn't matter,
2410 * though we'd want to check on additive. */
2411 }
2412 else {
2413 /* Outside range: modifier shouldn't contribute to the curve here,
2414 * though it does in other areas, so neither should the driver! */
2415 do_linear = false;
2416 }
2417 }
2418
2419 /* Only copy over results if none of the modifiers disagreed with this. */
2420 if (do_linear) {
2421 cvalue = evaltime;
2422 }
2423 }
2424 }
2425
2426 return evaluate_fcurve_ex(fcu, evaltime, cvalue);
2427}
2428
2430{
2431 return fcu->totvert == 0 && fcu->driver == nullptr &&
2433}
2434
2436 FCurve *fcu,
2437 const AnimationEvalContext *anim_eval_context)
2438{
2439 /* Only calculate + set curval (overriding the existing value) if curve has
2440 * any data which warrants this...
2441 */
2442 if (BKE_fcurve_is_empty(fcu)) {
2443 return 0.0f;
2444 }
2445
2446 /* Calculate and set curval (evaluates driver too if necessary). */
2447 float curval;
2448 if (fcu->driver) {
2449 curval = evaluate_fcurve_driver(anim_rna, fcu, fcu->driver, anim_eval_context);
2450 }
2451 else {
2452 curval = evaluate_fcurve(fcu, anim_eval_context->eval_time);
2453 }
2454 fcu->curval = curval; /* Debug display only, not thread safe! */
2455 return curval;
2456}
2457
2460/* -------------------------------------------------------------------- */
2465{
2466 /* Write all modifiers first (for faster reloading) */
2467 BLO_write_struct_list(writer, FModifier, fmodifiers);
2468
2469 /* Modifiers */
2470 LISTBASE_FOREACH (FModifier *, fcm, fmodifiers) {
2471 const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
2472
2473 /* Write the specific data */
2474 if (fmi && fcm->data) {
2475 /* firstly, just write the plain fmi->data struct */
2476 BLO_write_struct_by_name(writer, fmi->struct_name, fcm->data);
2477
2478 /* do any modifier specific stuff */
2479 switch (fcm->type) {
2481 FMod_Generator *data = static_cast<FMod_Generator *>(fcm->data);
2482
2483 /* write coefficients array */
2484 if (data->coefficients) {
2485 BLO_write_float_array(writer, data->arraysize, data->coefficients);
2486 }
2487
2488 break;
2489 }
2491 FMod_Envelope *data = static_cast<FMod_Envelope *>(fcm->data);
2492
2493 /* write envelope data */
2494 if (data->data) {
2495 BLO_write_struct_array(writer, FCM_EnvelopeData, data->totvert, data->data);
2496 }
2497
2498 break;
2499 }
2500 }
2501 }
2502 }
2503}
2504
2506{
2507 LISTBASE_FOREACH (FModifier *, fcm, fmodifiers) {
2508 const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
2509
2510 /* relink general data */
2511 if (fmi) {
2512 fcm->data = BLO_read_struct_by_name_array(reader, fmi->struct_name, 1, fcm->data);
2513 }
2514 else {
2516 fcm->data = nullptr;
2517 }
2518 fcm->curve = curve;
2519
2520 /* do relinking of data for specific types */
2521 switch (fcm->type) {
2523 FMod_Generator *data = (FMod_Generator *)fcm->data;
2524 BLO_read_float_array(reader, data->arraysize, &data->coefficients);
2525 break;
2526 }
2528 FMod_Envelope *data = (FMod_Envelope *)fcm->data;
2529
2530 BLO_read_struct_array(reader, FCM_EnvelopeData, data->totvert, &data->data);
2531
2532 break;
2533 }
2534 }
2535 }
2536}
2537
2539{
2540 /* curve data */
2541 if (fcu->bezt) {
2542 BLO_write_struct_array(writer, BezTriple, fcu->totvert, fcu->bezt);
2543 }
2544 if (fcu->fpt) {
2545 BLO_write_struct_array(writer, FPoint, fcu->totvert, fcu->fpt);
2546 }
2547
2548 if (fcu->rna_path) {
2549 BLO_write_string(writer, fcu->rna_path);
2550 }
2551
2552 /* driver data */
2553 if (fcu->driver) {
2554 ChannelDriver *driver = fcu->driver;
2555
2556 BLO_write_struct(writer, ChannelDriver, driver);
2557
2558 /* variables */
2559 BLO_write_struct_list(writer, DriverVar, &driver->variables);
2560 LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
2562 if (dtar->rna_path) {
2563 BLO_write_string(writer, dtar->rna_path);
2564 }
2565 }
2567 }
2568 }
2569
2570 /* write F-Modifiers */
2572}
2573
2575{
2576 BLO_write_struct_list(writer, FCurve, fcurves);
2577 LISTBASE_FOREACH (FCurve *, fcu, fcurves) {
2578 BKE_fcurve_blend_write_data(writer, fcu);
2579 }
2580}
2581
2583{
2584 /* curve data */
2585 BLO_read_struct_array(reader, BezTriple, fcu->totvert, &fcu->bezt);
2586 BLO_read_struct_array(reader, FPoint, fcu->totvert, &fcu->fpt);
2587
2588 /* rna path */
2589 BLO_read_string(reader, &fcu->rna_path);
2590
2591 /* group */
2592 BLO_read_struct(reader, bActionGroup, &fcu->grp);
2593
2594 /* clear disabled flag - allows disabled drivers to be tried again (#32155),
2595 * but also means that another method for "reviving disabled F-Curves" exists
2596 */
2597 fcu->flag &= ~FCURVE_DISABLED;
2598
2599 /* driver */
2600 BLO_read_struct(reader, ChannelDriver, &fcu->driver);
2601 if (fcu->driver) {
2602 ChannelDriver *driver = fcu->driver;
2603
2604 /* Compiled expression data will need to be regenerated
2605 * (old pointer may still be set here). */
2606 driver->expr_comp = nullptr;
2607 driver->expr_simple = nullptr;
2608
2609 /* Give the driver a fresh chance - the operating environment may be different now
2610 * (addons, etc. may be different) so the driver namespace may be sane now #32155. */
2612
2613 /* relink variables, targets and their paths */
2614 BLO_read_struct_list(reader, DriverVar, &driver->variables);
2615 LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
2617 /* only relink the targets being used */
2618 if (tarIndex < dvar->num_targets) {
2619 BLO_read_string(reader, &dtar->rna_path);
2620 }
2621 else {
2622 dtar->rna_path = nullptr;
2623 dtar->id = nullptr;
2624 }
2625 }
2627 }
2628 }
2629
2630 /* modifiers */
2632 BKE_fmodifiers_blend_read_data(reader, &fcu->modifiers, fcu);
2633}
2634
2636{
2637 /* Link F-Curve data to F-Curve again (non ID-libraries). */
2638 LISTBASE_FOREACH (FCurve *, fcu, fcurves) {
2639 BKE_fcurve_blend_read_data(reader, fcu);
2640 }
2641}
2642
Functions and classes to work with Actions.
Functions to work with AnimData.
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:89
@ NURB_HANDLE_TEST_EACH
Definition BKE_curve.hh:58
@ NURB_HANDLE_TEST_KNOT_ONLY
Definition BKE_curve.hh:68
void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
Definition curve.cc:3889
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:4046
@ FMI_TYPE_GENERATE_CURVE
Definition BKE_fcurve.hh:94
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)
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
float BLI_easing_sine_ease_in(float time, float begin, float change, float duration)
Definition easing.c:348
float BLI_easing_back_ease_out(float time, float begin, float change, float duration, float overshoot)
Definition easing.c:25
float BLI_easing_linear_ease(float time, float begin, float change, float duration)
Definition easing.c:282
float BLI_easing_bounce_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:66
float BLI_easing_quint_ease_out(float time, float begin, float change, float duration)
Definition easing.c:334
float BLI_easing_quart_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:320
float BLI_easing_circ_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:87
float BLI_easing_quart_ease_out(float time, float begin, float change, float duration)
Definition easing.c:314
float BLI_easing_bounce_ease_in(float time, float begin, float change, float duration)
Definition easing.c:61
float BLI_easing_circ_ease_in(float time, float begin, float change, float duration)
Definition easing.c:75
float BLI_easing_expo_ease_in(float time, float begin, float change, float duration)
Definition easing.c:255
float BLI_easing_expo_ease_out(float time, float begin, float change, float duration)
Definition easing.c:263
float BLI_easing_elastic_ease_in(float time, float begin, float change, float duration, float amplitude, float period)
Definition easing.c:146
float BLI_easing_quad_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:299
float BLI_easing_elastic_ease_out(float time, float begin, float change, float duration, float amplitude, float period)
Definition easing.c:179
float BLI_easing_cubic_ease_in(float time, float begin, float change, float duration)
Definition easing.c:96
float BLI_easing_elastic_ease_in_out(float time, float begin, float change, float duration, float amplitude, float period)
Definition easing.c:211
float BLI_easing_quint_ease_in(float time, float begin, float change, float duration)
Definition easing.c:329
float BLI_easing_sine_ease_out(float time, float begin, float change, float duration)
Definition easing.c:353
float BLI_easing_bounce_ease_out(float time, float begin, float change, float duration)
Definition easing.c:43
float BLI_easing_quad_ease_in(float time, float begin, float change, float duration)
Definition easing.c:287
float BLI_easing_quad_ease_out(float time, float begin, float change, float duration)
Definition easing.c:293
float BLI_easing_circ_ease_out(float time, float begin, float change, float duration)
Definition easing.c:81
float BLI_easing_cubic_ease_out(float time, float begin, float change, float duration)
Definition easing.c:102
float BLI_easing_back_ease_in(float time, float begin, float change, float duration, float overshoot)
Definition easing.c:18
float BLI_easing_quint_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:339
float BLI_easing_expo_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:271
float BLI_easing_quart_ease_in(float time, float begin, float change, float duration)
Definition easing.c:308
float BLI_easing_back_ease_in_out(float time, float begin, float change, float duration, float overshoot)
Definition easing.c:32
float BLI_easing_cubic_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:108
float BLI_easing_sine_ease_in_out(float time, float begin, float change, float duration)
Definition easing.c:358
sqrt(x)+1/max(0
#define GSET_ITER_INDEX(gs_iter_, gset_, i_)
Definition BLI_ghash.h:476
struct GSet GSet
Definition BLI_ghash.h:341
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.c:954
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition BLI_ghash.h:459
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1034
bool BLI_gset_add(GSet *gs, void *key)
Definition BLI_ghash.c:966
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
ListBase BLI_listbase_from_link(struct Link *some_link)
Definition listbase.cc:787
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
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)
Definition math_vector.c:21
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.c:25
#define STRNCPY(dst, src)
Definition BLI_string.h:593
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.c:29
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_read_struct_by_name_array(BlendDataReader *reader, const char *struct_name, uint32_t items_num, const void *old_address)
Definition readfile.cc:4873
void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr)
void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p)
Definition readfile.cc:4967
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:4992
void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr)
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)
#define BLT_I18NCONTEXT_ID_ACTION
#define CTX_DATA_(context, msgid)
typedef double(DMatrix)[4][4]
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
@ 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_INT_VALUES
@ FCURVE_DISCRETE_VALUES
@ FCURVE_PROTECTED
@ FCURVE_EXTRAPOLATE_CONSTANT
@ FCURVE_SMOOTH_NONE
#define BEZT_IS_AUTOH(bezt)
#define BEZT_ISSEL_ANY(bezt)
#define BEZT_DESEL_ALL(bezt)
@ 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
Object is a sort of wrapper for general info.
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)
#define SELECT
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)
void BKE_fcurve_bezt_shrink(FCurve *fcu, const int new_totvert)
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)
static CLG_LogRef LOG
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)
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)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
float evaltime
constexpr int64_t size() const
constexpr const char * data() const
local_group_size(16, 16) .push_constant(Type b
#define printf
#define floorf(x)
#define offsetof(t, d)
#define fabsf(x)
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
ccl_device_inline float2 floor(const float2 a)
ccl_device_inline float3 cos(float3 v)
static ulong * next
#define G(x, y, z)
FCurve * fcurve_find_in_action_slot(bAction *act, slot_handle_t slot_handle, FCurveDescriptor fcurve_descriptor)
const btScalar eps
Definition poly34.cpp:11
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_property_animateable(const PointerRNA *ptr, PropertyRNA *prop_orig)
PointerRNA RNA_pointer_create(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:1166
#define min(a, b)
Definition sort.c:32
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
unsigned int totvert
int active_keyframe_index
ListBase modifiers
FCM_EnvelopeData * data
char struct_name[64]
Definition BKE_fcurve.hh:60
char name[64]
float vec[2]
Definition DNA_ID.h:413
void * first
ListBase fcurves
ID * owner_id
Definition RNA_types.hh:40
void * data
Definition RNA_types.hh:42
float xmax
float xmin
float ymax
float ymin
float max
ccl_device_inline int abs(int x)
Definition util/math.h:120
PointerRNA * ptr
Definition wm_files.cc:4126