Blender V5.0
animrig/intern/fcurve.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cfloat>
10#include <cmath>
11#include <cstring>
12
13#include "ANIM_animdata.hh"
14#include "ANIM_fcurve.hh"
15#include "BKE_fcurve.hh"
16#include "BLI_math_base.h"
18#include "BLI_string.h"
19#include "DNA_anim_types.h"
20#include "MEM_guardedalloc.h"
21
22namespace blender::animrig {
23
24KeyframeSettings get_keyframe_settings(const bool from_userprefs)
25{
26 KeyframeSettings settings = {};
28 settings.handle = HD_AUTO_ANIM;
29 settings.interpolation = BEZT_IPO_BEZ;
30
31 if (from_userprefs) {
32 settings.interpolation = eBezTriple_Interpolation(U.ipo_new);
33 settings.handle = eBezTriple_Handle(U.keyhandles_new);
34 }
35 return settings;
36}
37
38const FCurve *fcurve_find(Span<const FCurve *> fcurves, const FCurveDescriptor &fcurve_descriptor)
39{
40 for (const FCurve *fcurve : fcurves) {
41 /* Check indices first, much cheaper than a string comparison. */
42 if (fcurve->array_index == fcurve_descriptor.array_index && fcurve->rna_path &&
43 StringRef(fcurve->rna_path) == fcurve_descriptor.rna_path)
44 {
45 return fcurve;
46 }
47 }
48 return nullptr;
49}
50FCurve *fcurve_find(Span<FCurve *> fcurves, const FCurveDescriptor &fcurve_descriptor)
51{
52 const FCurve *fcurve = fcurve_find(fcurves.cast<const FCurve *>(), fcurve_descriptor);
53 return const_cast<FCurve *>(fcurve);
54}
55
57{
59 fcu->rna_path = BLI_strdupn(fcurve_descriptor.rna_path.data(),
60 fcurve_descriptor.rna_path.size());
61 fcu->array_index = fcurve_descriptor.array_index;
63 fcu->auto_smoothing = U.auto_smoothing_new;
64
65 if (fcurve_descriptor.prop_type.has_value()) {
66 fcu->flag |= fcurve_flags_for_property_type(*fcurve_descriptor.prop_type);
67 }
68
69 /* Set the fcurve's color mode if needed/able. */
70 if ((U.keying_flag & KEYING_FLAG_XYZ2RGB) != 0 && fcurve_descriptor.prop_subtype.has_value()) {
71 switch (*fcurve_descriptor.prop_subtype) {
73 case PROP_XYZ:
74 case PROP_EULER:
75 case PROP_COLOR:
76 case PROP_COORDS:
78 break;
79
80 case PROP_QUATERNION:
82 break;
83
84 default:
85 /* Leave the color mode as default. */
86 break;
87 }
88 }
89
90 return fcu;
91}
92
94{
95 switch (prop_type) {
96 case PROP_FLOAT:
97 return eFCurve_Flags(0);
98 case PROP_INT:
99 /* Do integer (only 'whole' numbers) interpolation between all points. */
100 return FCURVE_INT_VALUES;
101 default:
102 /* Do 'discrete' (i.e. enum, boolean values which cannot take any intermediate
103 * values at all) interpolation between all points.
104 * - however, we must also ensure that evaluated values are only integers still.
105 */
107 }
108}
109
110bool fcurve_delete_keyframe_at_time(FCurve *fcurve, const float time)
111{
112 if (BKE_fcurve_is_protected(fcurve)) {
113 return false;
114 }
115 bool found;
116
117 const int index = BKE_fcurve_bezt_binarysearch_index(
118 fcurve->bezt, time, fcurve->totvert, &found);
119 if (!found) {
120 return false;
121 }
122
123 BKE_fcurve_delete_key(fcurve, index);
125
126 return true;
127}
128
130{
131 if (!fcurve_delete_keyframe_at_time(fcu, cfra)) {
132 return false;
133 }
134
135 /* Empty curves get automatically deleted. */
136 if (BKE_fcurve_is_empty(fcu)) {
137 animdata_fcurve_delete(adt, fcu);
138 }
139
140 return true;
141}
142
143/* ************************************************** */
144/* KEYFRAME INSERTION */
145
146/* -------------- BezTriple Insertion -------------------- */
147
148/* Change the Y position of a keyframe to match the input, adjusting handles. */
149static void replace_bezt_keyframe_ypos(BezTriple *dst, const BezTriple *bezt)
150{
151 /* Just change the values when replacing, so as to not overwrite handles. */
152 float dy = bezt->vec[1][1] - dst->vec[1][1];
153
154 /* Just apply delta value change to the handle values. */
155 dst->vec[0][1] += dy;
156 dst->vec[1][1] += dy;
157 dst->vec[2][1] += dy;
158
159 dst->f1 = bezt->f1;
160 dst->f2 = bezt->f2;
161 dst->f3 = bezt->f3;
162
163 /* TODO: perform some other operations? */
164}
165
167{
168 int i = 0;
169
170 /* Are there already keyframes? */
171 if (fcu->bezt) {
172 bool replace;
173 i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, bezt->vec[1][0], fcu->totvert, &replace);
174
175 /* Replace an existing keyframe? */
176 if (replace) {
177 /* `i` may in rare cases exceed array bounds. */
178 if ((i >= 0) && (i < fcu->totvert)) {
180 fcu->bezt[i] = *bezt;
181 }
182 else {
183 replace_bezt_keyframe_ypos(&fcu->bezt[i], bezt);
184 }
185
187 /* If replacing an end point of a cyclic curve without offset,
188 * modify the other end too. */
189 if (ELEM(i, 0, fcu->totvert - 1) && BKE_fcurve_get_cycle_type(fcu) == FCU_CYCLE_PERFECT)
190 {
191 replace_bezt_keyframe_ypos(&fcu->bezt[i == 0 ? fcu->totvert - 1 : 0], bezt);
192 }
193 }
194 }
195 }
196 /* Keyframing modes allow not replacing the keyframe. */
197 else if ((flag & INSERTKEY_REPLACE) == 0) {
198 /* Insert new - if we're not restricted to replacing keyframes only. */
199 BezTriple *newb = MEM_calloc_arrayN<BezTriple>(fcu->totvert + 1, "beztriple");
200
201 /* Add the beztriples that should occur before the beztriple to be pasted
202 * (originally in fcu). */
203 if (i > 0) {
204 memcpy(newb, fcu->bezt, i * sizeof(BezTriple));
205 }
206
207 /* Add beztriple to paste at index i. */
208 *(newb + i) = *bezt;
209
210 /* Add the beztriples that occur after the beztriple to be pasted (originally in fcu). */
211 if (i < fcu->totvert) {
212 memcpy(newb + i + 1, fcu->bezt + i, (fcu->totvert - i) * sizeof(BezTriple));
213 }
214
215 /* Replace (+ free) old with new, only if necessary to do so. */
216 MEM_freeN(fcu->bezt);
217 fcu->bezt = newb;
218
219 fcu->totvert++;
220 }
221 else {
222 return -1;
223 }
224 }
225 /* No keyframes yet, but can only add if...
226 * 1) keyframing modes say that keyframes can only be replaced, so adding new ones won't know
227 * 2) there are no samples on the curve
228 * NOTE: maybe we may want to allow this later when doing samples -> bezt conversions,
229 * but for now, having both is asking for trouble
230 */
231 else if ((flag & INSERTKEY_REPLACE) == 0 && (fcu->fpt == nullptr)) {
232 /* Create new keyframes array. */
233 fcu->bezt = MEM_callocN<BezTriple>("beztriple");
234 *(fcu->bezt) = *bezt;
235 fcu->totvert = 1;
236 }
237 /* Cannot add anything. */
238 else {
239 /* Return error code -1 to prevent any misunderstandings. */
240 return -1;
241 }
242
243 /* We need to return the index, so that some tools which do post-processing can
244 * detect where we added the BezTriple in the array.
245 */
246 return i;
247}
248
259static void subdivide_nonauto_handles(const FCurve *fcu,
260 BezTriple *bezt,
261 BezTriple *prev,
263{
264 if (prev->ipo != BEZT_IPO_BEZ || bezt->ipo != BEZT_IPO_BEZ) {
265 return;
266 }
267
268 /* Don't change Vector handles, or completely auto regions. */
269 const bool bezt_auto = BEZT_IS_AUTOH(bezt) || (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT);
270 const bool prev_auto = BEZT_IS_AUTOH(prev) || (prev->h2 == HD_VECT);
271 const bool next_auto = BEZT_IS_AUTOH(next) || (next->h1 == HD_VECT);
272 if (bezt_auto && prev_auto && next_auto) {
273 return;
274 }
275
276 /* Subdivide the curve. */
277 float delta;
278 if (!BKE_fcurve_bezt_subdivide_handles(bezt, prev, next, &delta)) {
279 return;
280 }
281
282 /* Decide when to force auto to manual. */
283 if (!BEZT_IS_AUTOH(bezt)) {
284 return;
285 }
286 if ((prev_auto || next_auto) && fcu->auto_smoothing == FCURVE_SMOOTH_CONT_ACCEL) {
287 const float hx = bezt->vec[1][0] - bezt->vec[0][0];
288 const float dx = bezt->vec[1][0] - prev->vec[1][0];
289
290 /* This mode always uses 1/3 of key distance for handle x size. */
291 const bool auto_works_well = fabsf(hx - dx / 3.0f) < 0.001f;
292 if (auto_works_well) {
293 return;
294 }
295 }
296
297 /* Turn off auto mode. */
298 bezt->h1 = bezt->h2 = HD_ALIGN;
299}
300
302 const float2 position,
303 const KeyframeSettings &settings,
304 const eFCurve_Flags fcu_flags)
305{
306 /* Set all three points, for nicer start position.
307 * NOTE: +/- 1 on vec.x for left and right handles is so that 'free' handles work ok...
308 */
309 beztr->vec[0][0] = position.x - 1.0f;
310 beztr->vec[0][1] = position.y;
311 beztr->vec[1][0] = position.x;
312 beztr->vec[1][1] = position.y;
313 beztr->vec[2][0] = position.x + 1.0f;
314 beztr->vec[2][1] = position.y;
315 beztr->f1 = beztr->f2 = beztr->f3 = SELECT;
316
317 beztr->h1 = beztr->h2 = settings.handle;
318 beztr->ipo = settings.interpolation;
319
320 /* Interpolation type used is constrained by the type of values the curve can take. */
321 if (fcu_flags & FCURVE_DISCRETE_VALUES) {
322 beztr->ipo = BEZT_IPO_CONST;
323 }
324 else if ((beztr->ipo == BEZT_IPO_BEZ) && (fcu_flags & FCURVE_INT_VALUES)) {
325 beztr->ipo = BEZT_IPO_LIN;
326 }
327
328 /* Set keyframe type value (supplied),
329 * which should come from the scene settings in most cases. */
330 BEZKEYTYPE_LVALUE(beztr) = settings.keyframe_type;
331
332 /* Set default values for "easing" interpolation mode settings.
333 * NOTE: Even if these modes aren't currently used, if users switch
334 * to these later, we want these to work in a sane way out of
335 * the box.
336 */
337
338 /* "back" easing - This value used to be used when overshoot=0, but that
339 * introduced discontinuities in how the param worked. */
340 beztr->back = 1.70158f;
341
342 /* "elastic" easing - Values here were hand-optimized for a default duration of
343 * ~10 frames (typical motion-graph motion length). */
344 beztr->amplitude = 0.8f;
345 beztr->period = 4.1f;
346}
347
363static bool new_key_needed(const FCurve &fcu, const float frame, const float value)
364{
365 if (fcu.totvert == 0) {
366 return true;
367 }
368
369 bool replace;
370 const int bezt_index = BKE_fcurve_bezt_binarysearch_index(
371 fcu.bezt, frame, fcu.totvert, &replace);
372
373 if (replace) {
374 /* If there is already a key, we only need to modify it if the proposed value is different. */
375 return fcu.bezt[bezt_index].vec[1][1] != value;
376 }
377
378 const int diff_ulp = 32;
379 const float fcu_eval = evaluate_fcurve(&fcu, frame);
380 /* No need to insert a key if the same value is already the value of the FCurve at that point. */
381 if (compare_ff_relative(fcu_eval, value, FLT_EPSILON, diff_ulp)) {
382 return false;
383 }
384
385 return true;
386}
387
393 const eFCU_Cycle_Type type,
394 float2 position)
395{
396 if (fcu.totvert < 2 || !fcu.bezt) {
397 return position;
398 }
399
400 if (type == FCU_CYCLE_NONE) {
401 return position;
402 }
403
404 BezTriple *first = &fcu.bezt[0], *last = &fcu.bezt[fcu.totvert - 1];
405 const float start = first->vec[1][0], end = last->vec[1][0];
406
407 if (start >= end) {
408 return position;
409 }
410
411 if (position.x < start || position.x > end) {
412 const float period = end - start;
413 const float step = floorf((position.x - start) / period);
414 position.x -= step * period;
415
416 if (type == FCU_CYCLE_OFFSET) {
417 /* Nasty check to handle the case when the modes are different better. */
418 FMod_Cycles *data = static_cast<FMod_Cycles *>(
419 static_cast<FModifier *>(fcu.modifiers.first)->data);
420 short mode = (step >= 0) ? data->after_mode : data->before_mode;
421
422 if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
423 position.y -= step * (last->vec[1][1] - first->vec[1][1]);
424 }
425 }
426 }
427
428 return position;
429}
430
432 const float2 position,
433 const KeyframeSettings &settings,
435{
436 BLI_assert(fcu != nullptr);
437
438 float2 remapped_position = position;
439 /* Adjust coordinates for cycle aware insertion. */
442 remapped_position = remap_cyclic_keyframe_location(*fcu, type, position);
443 if (type != FCU_CYCLE_PERFECT) {
444 /* Inhibit action from insert_bezt_fcurve unless it's a perfect cycle. */
446 }
447 }
448
449 if ((flag & INSERTKEY_NEEDED) && !new_key_needed(*fcu, remapped_position.x, remapped_position.y))
450 {
452 }
453
454 BezTriple beztr = {{{0}}};
455 initialize_bezt(&beztr, remapped_position, settings, eFCurve_Flags(fcu->flag));
456
457 uint oldTot = fcu->totvert;
458 int a;
459
460 /* Add temp beztriple to keyframes. */
461 a = insert_bezt_fcurve(fcu, &beztr, flag);
463
464 /* Key insertion failed. */
465 if (a < 0) {
466 /* TODO: we need more info from `insert_bezt_fcurve()` called above to
467 * return a more specific failure. */
469 }
470
471 /* Set handle-type and interpolation. */
472 if ((fcu->totvert > 2) && (flag & INSERTKEY_REPLACE) == 0) {
473 BezTriple *bezt = (fcu->bezt + a);
474
475 /* Set interpolation from previous (if available),
476 * but only if we didn't just replace some keyframe:
477 * - Replacement is indicated by no-change in number of verts.
478 * - When replacing, the user may have specified some interpolation that should be kept.
479 */
480 if (fcu->totvert > oldTot) {
481 if (a > 0) {
482 bezt->ipo = (bezt - 1)->ipo;
483 }
484 else if (a < fcu->totvert - 1) {
485 bezt->ipo = (bezt + 1)->ipo;
486 }
487
488 if (0 < a && a < (fcu->totvert - 1) && (flag & INSERTKEY_OVERWRITE_FULL) == 0) {
489 subdivide_nonauto_handles(fcu, bezt, bezt - 1, bezt + 1);
490 }
491 }
492 }
493
494 /* Don't recalculate handles if fast is set.
495 * - this is a hack to make importers faster
496 * - we may calculate twice (due to auto-handle needing to be calculated twice)
497 */
498 if ((flag & INSERTKEY_FAST) == 0) {
500 }
501
502 /* Return the index at which the keyframe was added. */
504}
505
507 const float start_frame,
508 const float sample_rate,
509 float *samples,
510 const int sample_count)
511{
512 for (int i = 0; i < sample_count; i++) {
513 const float evaluation_time = start_frame + (float(i) / sample_rate);
514 samples[i] = evaluate_fcurve(fcu, evaluation_time);
515 }
516}
517
519 const int2 range,
520 const BakeCurveRemove removal_mode)
521{
522 switch (removal_mode) {
523
526 break;
527 }
528
530 bool replace;
531
532 int before_index = BKE_fcurve_bezt_binarysearch_index(
533 fcu->bezt, range[0], fcu->totvert, &replace);
534
535 if (before_index > 0) {
536 BKE_fcurve_delete_keys(fcu, {0, uint(before_index)});
537 }
538
539 int after_index = BKE_fcurve_bezt_binarysearch_index(
540 fcu->bezt, range[1], fcu->totvert, &replace);
541 /* #OUT_RANGE is treated as exclusive on both ends. */
542 if (replace) {
543 after_index++;
544 }
545 if (after_index < fcu->totvert) {
546 BKE_fcurve_delete_keys(fcu, {uint(after_index), fcu->totvert});
547 }
548 break;
549 }
550
552 bool replace;
553 const int range_start_index = BKE_fcurve_bezt_binarysearch_index(
554 fcu->bezt, range[0], fcu->totvert, &replace);
555 int range_end_index = BKE_fcurve_bezt_binarysearch_index(
556 fcu->bezt, range[1], fcu->totvert, &replace);
557 if (replace) {
558 range_end_index++;
559 }
560
561 if (range_end_index > range_start_index) {
562 BKE_fcurve_delete_keys(fcu, {uint(range_start_index), uint(range_end_index)});
563 }
564 break;
565 }
566
567 default:
568 break;
569 }
570}
571
573 const int2 range,
574 const float step,
575 const BakeCurveRemove remove_existing)
576{
577 BLI_assert(step > 0);
578 const int sample_count = (range[1] - range[0]) / step + 1;
579 float *samples = MEM_calloc_arrayN<float>(sample_count, "Channel Bake Samples");
580 const float sample_rate = 1.0f / step;
581 sample_fcurve_segment(fcu, range[0], sample_rate, samples, sample_count);
582
583 if (remove_existing != BakeCurveRemove::NONE) {
584 remove_fcurve_key_range(fcu, range, remove_existing);
585 }
586
587 BezTriple *baked_keys = MEM_calloc_arrayN<BezTriple>(sample_count, "beztriple");
588
589 const KeyframeSettings settings = get_keyframe_settings(true);
590
591 for (int i = 0; i < sample_count; i++) {
592 BezTriple *key = &baked_keys[i];
593 float2 key_position = {range[0] + i * step, samples[i]};
594 initialize_bezt(key, key_position, settings, eFCurve_Flags(fcu->flag));
595 }
596
597 int merged_size;
598 BezTriple *merged_bezt = BKE_bezier_array_merge(
599 baked_keys, sample_count, fcu->bezt, fcu->totvert, &merged_size);
600
601 if (fcu->bezt != nullptr) {
602 /* Can happen if we removed all keys beforehand. */
603 MEM_freeN(fcu->bezt);
604 }
605 MEM_freeN(baked_keys);
606 fcu->bezt = merged_bezt;
607 fcu->totvert = merged_size;
608
609 MEM_freeN(samples);
611}
612
614 float frame, val;
615};
616
618{
619 const BezTriple *bezt, *start = nullptr, *end = nullptr;
620 TempFrameValCache *value_cache, *fp;
621 int sfra, range;
622 int i, n;
623
624 if (fcu->bezt == nullptr) {
625 return;
626 }
627
630
631 /* Find selected keyframes... once pair has been found, add keyframes. */
632 for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
633 /* check if selected, and which end this is */
634 if (BEZT_ISSEL_ANY(bezt)) {
635 if (start) {
636 /* If next bezt is also selected, don't start sampling yet,
637 * but instead wait for that one to reconsider, to avoid
638 * changing the curve when sampling consecutive segments
639 * (#53229)
640 */
641 if (i < fcu->totvert - 1) {
642 BezTriple *next = &fcu->bezt[i + 1];
643 if (BEZT_ISSEL_ANY(next)) {
644 continue;
645 }
646 }
647
648 end = bezt;
649
650 /* Cache values then add keyframes using these values, as adding
651 * keyframes while sampling will affect the outcome...
652 * - Only start sampling+adding from index=1, so that we don't overwrite original keyframe.
653 */
654 range = int(ceil(end->vec[1][0] - start->vec[1][0]));
655 sfra = int(floor(start->vec[1][0]));
656
657 if (range) {
658 value_cache = MEM_calloc_arrayN<TempFrameValCache>(range, "IcuFrameValCache");
659
660 /* Sample values. */
661 for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
662 fp->frame = float(sfra + n);
663 fp->val = evaluate_fcurve(fcu, fp->frame);
664 }
665
666 /* Add keyframes with these, tagging as 'breakdowns'. */
667 for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
669 fcu, {fp->frame, fp->val}, settings, INSERTKEY_NOFLAGS);
670 }
671
672 MEM_freeN(value_cache);
673
674 /* As we added keyframes, we need to compensate so that bezt is at the right place. */
675 bezt = fcu->bezt + i + range - 1;
676 i += (range - 1);
677 }
678
679 /* The current selection island has ended, so start again from scratch. */
680 start = nullptr;
681 end = nullptr;
682 }
683 else {
684 /* Just set start keyframe. */
685 start = bezt;
686 end = nullptr;
687 }
688 }
689 }
690
692}
693
694bool fcurve_frame_has_keyframe(const FCurve *fcu, const float frame)
695{
696 if (ELEM(nullptr, fcu, fcu->bezt)) {
697 return false;
698 }
699
700 if ((fcu->flag & FCURVE_MUTED) == 0) {
701 bool replace;
702 const int i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, frame, fcu->totvert, &replace);
703
704 /* #BKE_fcurve_bezt_binarysearch_index will set replace to be 0 or 1
705 * - obviously, 1 represents a match
706 */
707 if (replace) {
708 /* `i` may in rare cases exceed array bounds. */
709 if ((i >= 0) && (i < fcu->totvert)) {
710 return true;
711 }
712 }
713 }
714
715 return false;
716}
717
718} // namespace blender::animrig
Functions to work with AnimData.
Functions to modify FCurves.
FCurve * BKE_fcurve_create()
void BKE_fcurve_delete_keys(FCurve *fcu, blender::uint2 index_range)
int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[], float frame, int arraylen, bool *r_replace)
void BKE_fcurve_handles_recalc(FCurve *fcu)
eFCU_Cycle_Type
@ FCU_CYCLE_OFFSET
@ FCU_CYCLE_NONE
@ FCU_CYCLE_PERFECT
bool BKE_fcurve_is_empty(const FCurve *fcu)
eFCU_Cycle_Type BKE_fcurve_get_cycle_type(const FCurve *fcu)
void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt)
bool BKE_fcurve_is_protected(const FCurve *fcu)
bool BKE_fcurve_bezt_subdivide_handles(BezTriple *bezt, BezTriple *prev, BezTriple *next, float *r_pdelta)
float evaluate_fcurve(const FCurve *fcu, float evaltime)
BezTriple * BKE_bezier_array_merge(const BezTriple *a, int size_a, const BezTriple *b, int size_b, int *r_merged_size)
void BKE_fcurve_delete_key(FCurve *fcu, int index)
void BKE_fcurve_delete_keys_all(FCurve *fcu)
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE int compare_ff_relative(float a, float b, float max_diff, int max_ulps)
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.cc:30
unsigned int uint
#define ELEM(...)
@ FCM_EXTRAPOLATE_CYCLIC_OFFSET
@ FCURVE_COLOR_AUTO_RGB
@ FCURVE_COLOR_AUTO_YRGB
eInsertKeyFlags
@ INSERTKEY_FAST
@ INSERTKEY_CYCLE_AWARE
@ INSERTKEY_OVERWRITE_FULL
@ INSERTKEY_REPLACE
@ INSERTKEY_NEEDED
@ INSERTKEY_NOFLAGS
eFCurve_Flags
@ FCURVE_MUTED
@ FCURVE_INT_VALUES
@ FCURVE_SELECTED
@ FCURVE_DISCRETE_VALUES
@ FCURVE_VISIBLE
@ FCURVE_SMOOTH_CONT_ACCEL
eBezTriple_Handle
@ HD_AUTO_ANIM
@ HD_VECT
@ HD_ALIGN
eBezTriple_Interpolation
@ BEZT_IPO_CONST
@ BEZT_IPO_BEZ
@ BEZT_IPO_LIN
@ BEZT_KEYTYPE_BREAKDOWN
@ BEZT_KEYTYPE_KEYFRAME
#define BEZT_IS_AUTOH(bezt)
#define BEZT_ISSEL_ANY(bezt)
#define BEZKEYTYPE_LVALUE(bezt)
@ KEYING_FLAG_XYZ2RGB
Read Guarded memory(de)allocation.
PropertyType
Definition RNA_types.hh:161
@ PROP_FLOAT
Definition RNA_types.hh:164
@ PROP_INT
Definition RNA_types.hh:163
@ PROP_XYZ
Definition RNA_types.hh:269
@ PROP_COLOR
Definition RNA_types.hh:260
@ PROP_EULER
Definition RNA_types.hh:266
@ PROP_COORDS
Definition RNA_types.hh:274
@ PROP_TRANSLATION
Definition RNA_types.hh:261
@ PROP_QUATERNION
Definition RNA_types.hh:267
#define U
BMesh const char void * data
Span< NewT > constexpr cast() const
Definition BLI_span.hh:418
constexpr int64_t size() const
constexpr const char * data() const
nullptr float
#define SELECT
#define floor
#define ceil
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static ulong * next
static float2 remap_cyclic_keyframe_location(const FCurve &fcu, const eFCU_Cycle_Type type, float2 position)
void animdata_fcurve_delete(AnimData *adt, FCurve *fcu)
Definition animdata.cc:251
KeyframeSettings get_keyframe_settings(bool from_userprefs)
bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame)
static bool new_key_needed(const FCurve &fcu, const float frame, const float value)
eFCurve_Flags fcurve_flags_for_property_type(PropertyType prop_type)
FCurve * create_fcurve_for_channel(const FCurveDescriptor &fcurve_descriptor)
static void remove_fcurve_key_range(FCurve *fcu, const int2 range, const BakeCurveRemove removal_mode)
void initialize_bezt(BezTriple *beztr, float2 position, const KeyframeSettings &settings, eFCurve_Flags fcu_flags)
void sample_fcurve_segment(const FCurve *fcu, float start_frame, float sample_rate, float *samples, int sample_count)
bool fcurve_delete_keyframe_at_time(FCurve *fcurve, float time)
SingleKeyingResult insert_vert_fcurve(FCurve *fcu, const float2 position, const KeyframeSettings &settings, eInsertKeyFlags flag)
Main Key-framing API call.
void bake_fcurve(FCurve *fcu, blender::int2 range, float step, BakeCurveRemove remove_existing)
static void subdivide_nonauto_handles(const FCurve *fcu, BezTriple *bezt, BezTriple *prev, BezTriple *next)
const FCurve * fcurve_find(Span< const FCurve * > fcurves, const FCurveDescriptor &fcurve_descriptor)
int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
Lesser Key-framing API call.
bool delete_keyframe_fcurve_legacy(AnimData *adt, FCurve *fcu, float cfra)
static void replace_bezt_keyframe_ypos(BezTriple *dst, const BezTriple *bezt)
void bake_fcurve_segments(FCurve *fcu)
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
#define floorf
#define fabsf
float vec[3][3]
char * rna_path
FPoint * fpt
BezTriple * bezt
int array_index
unsigned int totvert
char auto_smoothing
ListBase modifiers
void * first
std::optional< PropertySubType > prop_subtype
std::optional< PropertyType > prop_type
eBezTriple_Interpolation interpolation
eBezTriple_KeyframeType keyframe_type
i
Definition text_draw.cc:230
uint8_t flag
Definition wm_window.cc:145