Blender V4.3
keyframes_keylist.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/* System includes ----------------------------------------------------- */
10
11#include <algorithm>
12#include <cfloat>
13#include <cmath>
14#include <cstdlib>
15#include <cstring>
16#include <functional>
17#include <optional>
18
19#include "MEM_guardedalloc.h"
20
21#include "BLI_array.hh"
22#include "BLI_bounds.hh"
23#include "BLI_listbase.h"
24#include "BLI_range.h"
25#include "BLI_utildefines.h"
26
27#include "DNA_anim_types.h"
28#include "DNA_cachefile_types.h"
30#include "DNA_mask_types.h"
31#include "DNA_object_types.h"
32#include "DNA_scene_types.h"
33
34#include "BKE_fcurve.hh"
35#include "BKE_grease_pencil.hh"
36
37#include "ED_anim_api.hh"
39
40#include "ANIM_action.hh"
41
42using namespace blender;
43
44/* *************************** Keyframe Processing *************************** */
45
46/* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
47
48BLI_INLINE bool is_cfra_eq(const float a, const float b)
49{
51}
52
53BLI_INLINE bool is_cfra_lt(const float a, const float b)
54{
55 return (b - a) > BEZT_BINARYSEARCH_THRESH;
56}
57
58/* --------------- */
59
68
70 /* Number of ActKeyColumn's in the keylist. */
71 size_t column_len = 0;
72
74
75 /* Before initializing the runtime, the key_columns list base is used to quickly add columns.
76 * Contains `ActKeyColumn`. Should not be used after runtime is initialized. */
77 ListBase /*ActKeyColumn*/ key_columns;
78 /* Last accessed column in the key_columns list base. Inserting columns are typically done in
79 * order. The last accessed column is used as starting point to search for a location to add or
80 * update the next column. */
81 std::optional<ActKeyColumn *> last_accessed_column = std::nullopt;
82
83 struct {
84 /* When initializing the runtime the columns from the list base `AnimKeyList.key_columns` are
85 * transferred to an array to support binary searching and index based access. */
87 /* Wrapper around runtime.key_columns so it can still be accessed as a ListBase.
88 * Elements are owned by `runtime.key_columns`. */
89 ListBase /*ActKeyColumn*/ list_wrapper;
91
93 {
94 BLI_listbase_clear(&this->key_columns);
95 BLI_listbase_clear(&this->runtime.list_wrapper);
96 }
97
99 {
100 BLI_freelistN(&this->key_columns);
101 BLI_listbase_clear(&this->runtime.list_wrapper);
102 }
103
104#ifdef WITH_CXX_GUARDEDALLOC
105 MEM_CXX_CLASS_ALLOC_FUNCS("editors:AnimKeylist")
106#endif
107};
108
110{
111 AnimKeylist *keylist = new AnimKeylist();
112 return keylist;
113}
114
116{
117 BLI_assert(keylist);
118 delete keylist;
119}
120
122{
123 size_t index;
124 LISTBASE_FOREACH_INDEX (ActKeyColumn *, key, &keylist->key_columns, index) {
125 keylist->runtime.key_columns[index] = *key;
126 }
127}
128
130{
131 for (size_t index = 0; index < keylist->column_len; index++) {
132 const bool is_first = (index == 0);
133 keylist->runtime.key_columns[index].prev = is_first ? nullptr :
134 &keylist->runtime.key_columns[index - 1];
135 const bool is_last = (index == keylist->column_len - 1);
136 keylist->runtime.key_columns[index].next = is_last ? nullptr :
137 &keylist->runtime.key_columns[index + 1];
138 }
139}
140
142{
143 if (ED_keylist_is_empty(keylist)) {
145 return;
146 }
147
148 keylist->runtime.list_wrapper.first = keylist->runtime.key_columns.data();
149 keylist->runtime.list_wrapper.last = &keylist->runtime.key_columns[keylist->column_len - 1];
150}
151
153{
155
157
158 /* Convert linked list to array to support fast searching. */
160 /* Ensure that the array can also be used as a listbase for external usages. */
163
164 keylist->is_runtime_initialized = true;
165}
166
168{
170 keylist->last_accessed_column.reset();
171}
172
174{
175 if (keylist->is_runtime_initialized) {
176 return;
177 }
179}
180
182 const float cfra)
183{
185 const ActKeyColumn *begin = std::begin(keylist->runtime.key_columns);
186 const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
187 ActKeyColumn value;
188 value.cfra = cfra;
189
190 const ActKeyColumn *found_column = std::lower_bound(
191 begin, end, value, [](const ActKeyColumn &column, const ActKeyColumn &other) {
192 return is_cfra_lt(column.cfra, other.cfra);
193 });
194 return found_column;
195}
196
198 const float cfra)
199{
201 const ActKeyColumn *begin = std::begin(keylist->runtime.key_columns);
202 const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
203 ActKeyColumn value;
204 value.cfra = cfra;
205
206 const ActKeyColumn *found_column = std::upper_bound(
207 begin, end, value, [](const ActKeyColumn &column, const ActKeyColumn &other) {
208 return is_cfra_lt(column.cfra, other.cfra);
209 });
210 return found_column;
211}
212
213const ActKeyColumn *ED_keylist_find_exact(const AnimKeylist *keylist, const float cfra)
214{
216 "ED_keylist_prepare_for_direct_access needs to be called before searching.");
217
218 if (ED_keylist_is_empty(keylist)) {
219 return nullptr;
220 }
221
222 const ActKeyColumn *found_column = ED_keylist_find_lower_bound(keylist, cfra);
223
224 const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
225 if (found_column == end) {
226 return nullptr;
227 }
228 if (is_cfra_eq(found_column->cfra, cfra)) {
229 return found_column;
230 }
231 return nullptr;
232}
233
234const ActKeyColumn *ED_keylist_find_next(const AnimKeylist *keylist, const float cfra)
235{
237 "ED_keylist_prepare_for_direct_access needs to be called before searching.");
238
239 if (ED_keylist_is_empty(keylist)) {
240 return nullptr;
241 }
242
243 const ActKeyColumn *found_column = ED_keylist_find_upper_bound(keylist, cfra);
244
245 const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
246 if (found_column == end) {
247 return nullptr;
248 }
249 return found_column;
250}
251
252const ActKeyColumn *ED_keylist_find_prev(const AnimKeylist *keylist, const float cfra)
253{
255 "ED_keylist_prepare_for_direct_access needs to be called before searching.");
256
257 if (ED_keylist_is_empty(keylist)) {
258 return nullptr;
259 }
260
261 const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
262 const ActKeyColumn *found_column = ED_keylist_find_lower_bound(keylist, cfra);
263
264 if (found_column == end) {
265 /* Nothing found, return the last item. */
266 return end - 1;
267 }
268
269 const ActKeyColumn *prev_column = found_column->prev;
270 return prev_column;
271}
272
274 const Range2f frame_range)
275{
277 "ED_keylist_prepare_for_direct_access needs to be called before searching.");
278
279 if (ED_keylist_is_empty(keylist)) {
280 return nullptr;
281 }
282
283 const ActKeyColumn *column = ED_keylist_find_lower_bound(keylist, frame_range.min);
284 const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
285 if (column == end) {
286 return nullptr;
287 }
288 if (column->cfra >= frame_range.max) {
289 return nullptr;
290 }
291 return column;
292}
293
295{
297 keylist->is_runtime_initialized,
298 "ED_keylist_prepare_for_direct_access needs to be called before accessing array.");
299 return keylist->runtime.key_columns.data();
300}
301
303{
304 return keylist->column_len;
305}
306
308{
309 return keylist->column_len == 0;
310}
311
313{
314 if (keylist->is_runtime_initialized) {
315 return &keylist->runtime.list_wrapper;
316 }
317 return &keylist->key_columns;
318}
319
320static void keylist_first_last(const AnimKeylist *keylist,
321 const ActKeyColumn **first_column,
322 const ActKeyColumn **last_column)
323{
324 if (keylist->is_runtime_initialized) {
325 *first_column = keylist->runtime.key_columns.data();
326 *last_column = &keylist->runtime.key_columns[keylist->column_len - 1];
327 }
328 else {
329 *first_column = static_cast<const ActKeyColumn *>(keylist->key_columns.first);
330 *last_column = static_cast<const ActKeyColumn *>(keylist->key_columns.last);
331 }
332}
333
334bool ED_keylist_all_keys_frame_range(const AnimKeylist *keylist, Range2f *r_frame_range)
335{
336 BLI_assert(r_frame_range);
337
338 if (ED_keylist_is_empty(keylist)) {
339 return false;
340 }
341
342 const ActKeyColumn *first_column;
343 const ActKeyColumn *last_column;
344 keylist_first_last(keylist, &first_column, &last_column);
345 r_frame_range->min = first_column->cfra;
346 r_frame_range->max = last_column->cfra;
347
348 return true;
349}
350
351bool ED_keylist_selected_keys_frame_range(const AnimKeylist *keylist, Range2f *r_frame_range)
352{
353 BLI_assert(r_frame_range);
354
355 if (ED_keylist_is_empty(keylist)) {
356 return false;
357 }
358
359 const ActKeyColumn *first_column;
360 const ActKeyColumn *last_column;
361 keylist_first_last(keylist, &first_column, &last_column);
362 while (first_column && !(first_column->sel & SELECT)) {
363 first_column = first_column->next;
364 }
365 while (last_column && !(last_column->sel & SELECT)) {
366 last_column = last_column->prev;
367 }
368 if (!first_column || !last_column || first_column == last_column) {
369 return false;
370 }
371 r_frame_range->min = first_column->cfra;
372 r_frame_range->max = last_column->cfra;
373
374 return true;
375}
376
377/* Set of references to three logically adjacent keys. */
379 /* Current keyframe. */
381
382 /* Logical neighbors. May be nullptr. */
384};
385
386/* Categorize the interpolation & handle type of the keyframe. */
388{
389 if (bezt->h1 == HD_AUTO_ANIM && bezt->h2 == HD_AUTO_ANIM) {
391 }
392 if (ELEM(bezt->h1, HD_AUTO_ANIM, HD_AUTO) && ELEM(bezt->h2, HD_AUTO_ANIM, HD_AUTO)) {
394 }
395 if (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) {
397 }
398 if (ELEM(HD_FREE, bezt->h1, bezt->h2)) {
400 }
402}
403
404/* Determine if the keyframe is an extreme by comparing with neighbors.
405 * Ends of fixed-value sections and of the whole curve are also marked.
406 */
408{
409 if (chain->prev == nullptr && chain->next == nullptr) {
411 }
412
413 /* Keyframe values for the current one and neighbors. */
414 const float cur_y = chain->cur->vec[1][1];
415 float prev_y = cur_y, next_y = cur_y;
416
417 if (chain->prev && !IS_EQF(cur_y, chain->prev->vec[1][1])) {
418 prev_y = chain->prev->vec[1][1];
419 }
420 if (chain->next && !IS_EQF(cur_y, chain->next->vec[1][1])) {
421 next_y = chain->next->vec[1][1];
422 }
423
424 /* Static hold. */
425 if (prev_y == cur_y && next_y == cur_y) {
427 }
428
429 /* Middle of an incline. */
430 if ((prev_y < cur_y && next_y > cur_y) || (prev_y > cur_y && next_y < cur_y)) {
432 }
433
434 /* Bezier handle values for the overshoot check. */
435 const bool l_bezier = chain->prev && chain->prev->ipo == BEZT_IPO_BEZ;
436 const bool r_bezier = chain->next && chain->cur->ipo == BEZT_IPO_BEZ;
437 const float handle_l = l_bezier ? chain->cur->vec[0][1] : cur_y;
438 const float handle_r = r_bezier ? chain->cur->vec[2][1] : cur_y;
439
440 /* Detect extremes. One of the neighbors is allowed to be equal to current. */
441 if (prev_y < cur_y || next_y < cur_y) {
442 const bool is_overshoot = (handle_l > cur_y || handle_r > cur_y);
443
445 (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0));
446 }
447
448 if (prev_y > cur_y || next_y > cur_y) {
449 const bool is_overshoot = (handle_l < cur_y || handle_r < cur_y);
450
452 (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0));
453 }
454
456}
457
458/* New node callback used for building ActKeyColumns from BezTripleChain */
459static ActKeyColumn *nalloc_ak_bezt(void *data)
460{
461 ActKeyColumn *ak = static_cast<ActKeyColumn *>(
462 MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn"));
463 const BezTripleChain *chain = static_cast<const BezTripleChain *>(data);
464 const BezTriple *bezt = chain->cur;
465
466 /* store settings based on state of BezTriple */
467 ak->cfra = bezt->vec[1][0];
468 ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0;
469 ak->key_type = BEZKEYTYPE(bezt);
470 ak->handle_type = bezt_handle_type(bezt);
471 ak->extreme_type = bezt_extreme_type(chain);
472
473 /* count keyframes in this column */
474 ak->totkey = 1;
475
476 return ak;
477}
478
479/* Node updater callback used for building ActKeyColumns from BezTripleChain */
480static void nupdate_ak_bezt(ActKeyColumn *ak, void *data)
481{
482 const BezTripleChain *chain = static_cast<const BezTripleChain *>(data);
483 const BezTriple *bezt = chain->cur;
484
485 /* set selection status and 'touched' status */
486 if (BEZT_ISSEL_ANY(bezt)) {
487 ak->sel = SELECT;
488 }
489
490 ak->totkey++;
491
492 /* For keyframe type, 'proper' keyframes have priority over breakdowns
493 * (and other types for now). */
494 if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME) {
496 }
497
498 /* For interpolation type, select the highest value (enum is sorted). */
500
501 /* For extremes, detect when combining different states. */
502 const char new_extreme = bezt_extreme_type(chain);
503
504 if (new_extreme != ak->extreme_type) {
505 /* Replace the flat status without adding mixed. */
507 ak->extreme_type = new_extreme;
508 }
509 else if (new_extreme != KEYFRAME_EXTREME_FLAT) {
510 ak->extreme_type |= (new_extreme | KEYFRAME_EXTREME_MIXED);
511 }
512 }
513}
514
515/* ......... */
516/* New node callback used for building ActKeyColumns from GPencil frames */
517static ActKeyColumn *nalloc_ak_cel(void *data)
518{
519 ActKeyColumn *ak = static_cast<ActKeyColumn *>(
520 MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnCel"));
521 GreasePencilCel &cel = *static_cast<GreasePencilCel *>(data);
522
523 /* Store settings based on state of BezTriple */
524 ak->cfra = cel.frame_number;
525 ak->sel = (cel.frame.flag & SELECT) != 0;
527
528 /* Count keyframes in this column */
529 ak->totkey = 1;
530 /* Set as visible block. */
531 ak->totblock = 1;
532 ak->block.sel = ak->sel;
534
535 return ak;
536}
537
538/* Node updater callback used for building ActKeyColumns from GPencil frames */
539static void nupdate_ak_cel(ActKeyColumn *ak, void *data)
540{
541 GreasePencilCel &cel = *static_cast<GreasePencilCel *>(data);
542
543 /* Update selection status. */
544 if (cel.frame.flag & GP_FRAME_SELECTED) {
545 ak->sel = SELECT;
546 }
547
548 ak->totkey++;
549
550 /* Update keytype status. */
551 if (cel.frame.type == BEZT_KEYTYPE_KEYFRAME) {
553 }
554}
555
556/* ......... */
557
558/* New node callback used for building ActKeyColumns from GPencil frames. */
560{
561 ActKeyColumn *ak = static_cast<ActKeyColumn *>(
562 MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF"));
563 const bGPDframe *gpf = (bGPDframe *)data;
564
565 /* store settings based on state of BezTriple */
566 ak->cfra = gpf->framenum;
567 ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0;
569
570 /* Count keyframes in this column. */
571 ak->totkey = 1;
572 /* Set as visible block. */
573 ak->totblock = 1;
574 ak->block.sel = ak->sel;
576
577 return ak;
578}
579
580/* Node updater callback used for building ActKeyColumns from GPencil frames. */
581static void nupdate_ak_gpframe(ActKeyColumn *ak, void *data)
582{
583 bGPDframe *gpf = (bGPDframe *)data;
584
585 /* Set selection status and 'touched' status. */
586 if (gpf->flag & GP_FRAME_SELECT) {
587 ak->sel = SELECT;
588 }
589
590 ak->totkey++;
591
592 /* For keyframe type, 'proper' keyframes have priority over breakdowns
593 * (and other types for now). */
594 if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME) {
596 }
597}
598
599/* ......... */
600
601/* New node callback used for building ActKeyColumns from GPencil frames */
603{
604 ActKeyColumn *ak = static_cast<ActKeyColumn *>(
605 MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF"));
606 const MaskLayerShape *masklay_shape = (const MaskLayerShape *)data;
607
608 /* Store settings based on state of BezTriple. */
609 ak->cfra = masklay_shape->frame;
610 ak->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? SELECT : 0;
611
612 /* Count keyframes in this column. */
613 ak->totkey = 1;
614
615 return ak;
616}
617
618/* Node updater callback used for building ActKeyColumns from GPencil frames */
619static void nupdate_ak_masklayshape(ActKeyColumn *ak, void *data)
620{
621 MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
622
623 /* Set selection status and 'touched' status. */
624 if (masklay_shape->flag & MASK_SHAPE_SELECT) {
625 ak->sel = SELECT;
626 }
627
628 ak->totkey++;
629}
630
631/* --------------- */
632using KeylistCreateColumnFunction = std::function<ActKeyColumn *(void *userdata)>;
633using KeylistUpdateColumnFunction = std::function<void(ActKeyColumn *, void *)>;
634
635/* `ED_keylist_find_neighbor_front_to_back` is called before the runtime can be initialized so we
636 * cannot use bin searching. */
638{
639 while (cursor->next && cursor->next->cfra <= cfra) {
640 cursor = cursor->next;
641 }
642 return cursor;
643}
644
645/* `ED_keylist_find_neighbor_back_to_front` is called before the runtime can be initialized so we
646 * cannot use bin searching. */
648{
649 while (cursor->prev && cursor->prev->cfra >= cfra) {
650 cursor = cursor->prev;
651 }
652 return cursor;
653}
654
655/*
656 * `ED_keylist_find_exact_or_neighbor_column` is called before the runtime can be initialized so
657 * we cannot use bin searching.
658 *
659 * This function is called to add or update columns in the keylist.
660 * Typically columns are sorted by frame number so keeping track of the last_accessed_column
661 * reduces searching.
662 */
664{
666 if (ED_keylist_is_empty(keylist)) {
667 return nullptr;
668 }
669
670 ActKeyColumn *cursor = keylist->last_accessed_column.value_or(
671 static_cast<ActKeyColumn *>(keylist->key_columns.first));
672 if (!is_cfra_eq(cursor->cfra, cfra)) {
673 const bool walking_direction_front_to_back = cursor->cfra <= cfra;
674 if (walking_direction_front_to_back) {
675 cursor = ED_keylist_find_neighbor_front_to_back(cursor, cfra);
676 }
677 else {
678 cursor = ED_keylist_find_neighbor_back_to_front(cursor, cfra);
679 }
680 }
681
682 keylist->last_accessed_column = cursor;
683 return cursor;
684}
685
687 float cfra,
689 KeylistUpdateColumnFunction update_func,
690 void *userdata)
691{
693 !keylist->is_runtime_initialized,
694 "Modifying AnimKeylist isn't allowed after runtime is initialized "
695 "keylist->key_columns/columns_len will get out of sync with runtime.key_columns.");
696 if (ED_keylist_is_empty(keylist)) {
697 ActKeyColumn *key_column = create_func(userdata);
698 BLI_addhead(&keylist->key_columns, key_column);
699 keylist->column_len += 1;
700 keylist->last_accessed_column = key_column;
701 return;
702 }
703
705 if (is_cfra_eq(nearest->cfra, cfra)) {
706 update_func(nearest, userdata);
707 }
708 else if (is_cfra_lt(nearest->cfra, cfra)) {
709 ActKeyColumn *key_column = create_func(userdata);
710 BLI_insertlinkafter(&keylist->key_columns, nearest, key_column);
711 keylist->column_len += 1;
712 keylist->last_accessed_column = key_column;
713 }
714 else {
715 ActKeyColumn *key_column = create_func(userdata);
716 BLI_insertlinkbefore(&keylist->key_columns, nearest, key_column);
717 keylist->column_len += 1;
718 keylist->last_accessed_column = key_column;
719 }
720}
721
722/* Add the given BezTriple to the given 'list' of Keyframes */
724{
725 if (ELEM(nullptr, keylist, bezt)) {
726 return;
727 }
728
729 float cfra = bezt->cur->vec[1][0];
731}
732
733/* Add the given GPencil Frame to the given 'list' of Keyframes */
735{
736 if (ELEM(nullptr, keylist, gpf)) {
737 return;
738 }
739
740 float cfra = gpf->framenum;
742}
743
744/* Add the given MaskLayerShape Frame to the given 'list' of Keyframes */
745static void add_masklay_to_keycolumns_list(AnimKeylist *keylist, MaskLayerShape *masklay_shape)
746{
747 if (ELEM(nullptr, keylist, masklay_shape)) {
748 return;
749 }
750
751 float cfra = masklay_shape->frame;
753 keylist, cfra, nalloc_ak_masklayshape, nupdate_ak_masklayshape, masklay_shape);
754}
755
756/* ActKeyBlocks (Long Keyframes) ------------------------------------------ */
757
759
761 const BezTriple *prev,
762 const BezTriple *beztn)
763{
764 memset(info, 0, sizeof(ActKeyBlockInfo));
765
766 if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) {
767 /* Animator tagged a "moving hold"
768 * - Previous key must also be tagged as a moving hold, otherwise
769 * we're just dealing with the first of a pair, and we don't
770 * want to be creating any phantom holds...
771 */
772 if (BEZKEYTYPE(prev) == BEZT_KEYTYPE_MOVEHOLD) {
774 }
775 }
776
777 /* Check for same values...
778 * - Handles must have same central value as each other
779 * - Handles which control that section of the curve must be constant
780 */
781 if (IS_EQF(beztn->vec[1][1], prev->vec[1][1])) {
782 bool hold;
783
784 /* Only check handles in case of actual bezier interpolation. */
785 if (prev->ipo == BEZT_IPO_BEZ) {
786 hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) &&
787 IS_EQF(prev->vec[1][1], prev->vec[2][1]);
788 }
789 /* This interpolation type induces movement even between identical columns. */
790 else {
791 hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC);
792 }
793
794 if (hold) {
796 }
797 }
798
799 /* Remember non-bezier interpolation info. */
800 if (prev->ipo != BEZT_IPO_BEZ) {
802 }
803
804 info->sel = BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn);
805}
806
808{
809 /* New curve and block. */
810 if (col->totcurve <= 1 && col->totblock == 0) {
811 memcpy(&col->block, block, sizeof(ActKeyBlockInfo));
812 }
813 /* Existing curve. */
814 else {
815 col->block.conflict |= (col->block.flag ^ block->flag);
816 col->block.flag |= block->flag;
817 col->block.sel |= block->sel;
818 }
819
820 if (block->flag) {
821 col->totblock++;
822 }
823}
824
825static void add_bezt_to_keyblocks_list(AnimKeylist *keylist, BezTriple *bezt, const int bezt_len)
826{
827 ActKeyColumn *col = static_cast<ActKeyColumn *>(keylist->key_columns.first);
828
829 if (bezt && bezt_len >= 2) {
830 ActKeyBlockInfo block;
831
832 /* Find the first key column while inserting dummy blocks. */
833 for (; col != nullptr && is_cfra_lt(col->cfra, bezt[0].vec[1][0]); col = col->next) {
835 }
836
837 BLI_assert(col != nullptr);
838
839 /* Insert real blocks. */
840 for (int v = 1; col != nullptr && v < bezt_len; v++, bezt++) {
841 /* Wrong order of bezier keys: resync position. */
842 if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) {
843 /* Backtrack to find the right location. */
844 if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) {
846
847 BLI_assert(newcol);
848 BLI_assert(newcol->cfra == col->cfra);
849
850 col = newcol;
851 /* The previous keyblock is garbage too. */
852 if (col->prev != nullptr) {
854 }
855 }
856
857 continue;
858 }
859
860 /* In normal situations all keyframes are sorted. However, while keys are transformed, they
861 * may change order and then this assertion no longer holds. The effect is that the drawing
862 * isn't perfect during the transform; the "constant value" bars aren't updated until the
863 * transformation is confirmed. */
864 // BLI_assert(is_cfra_eq(col->cfra, bezt[0].vec[1][0]));
865
866 compute_keyblock_data(&block, bezt, bezt + 1);
867
868 for (; col != nullptr && is_cfra_lt(col->cfra, bezt[1].vec[1][0]); col = col->next) {
869 add_keyblock_info(col, &block);
870 }
871
872 BLI_assert(col != nullptr);
873 }
874 }
875
876 /* Insert dummy blocks at the end. */
877 for (; col != nullptr; col = col->next) {
879 }
880}
881
882/* Walk through columns and propagate blocks and totcurve.
883 *
884 * This must be called even by animation sources that don't generate
885 * keyblocks to keep the data structure consistent after adding columns.
886 */
887static void update_keyblocks(AnimKeylist *keylist, BezTriple *bezt, const int bezt_len)
888{
889 /* Find the curve count. */
890 int max_curve = 0;
891
893 max_curve = std::max(max_curve, int(col->totcurve));
894 }
895
896 /* Propagate blocks to inserted keys. */
897 ActKeyColumn *prev_ready = nullptr;
898
900 /* Pre-existing column. */
901 if (col->totcurve > 0) {
902 prev_ready = col;
903 }
904 /* Newly inserted column, so copy block data from previous. */
905 else if (prev_ready != nullptr) {
906 col->totblock = prev_ready->totblock;
907 memcpy(&col->block, &prev_ready->block, sizeof(ActKeyBlockInfo));
908 }
909
910 col->totcurve = max_curve + 1;
911 }
912
913 /* Add blocks on top. */
914 add_bezt_to_keyblocks_list(keylist, bezt, bezt_len);
915}
916
917/* --------- */
918
920{
921 return ac != nullptr && ac->next != nullptr && ac->totblock > 0;
922}
923
925{
926 if (!actkeyblock_is_valid(ac)) {
927 return 0;
928 }
929
931 return (ac->block.flag & ~ac->block.conflict) & hold_mask;
932}
933
934/* *************************** Keyframe List Conversions *************************** */
935
937 AnimKeylist *keylist,
938 const int saction_flag,
939 blender::float2 range)
940{
941 if (!ac) {
942 return;
943 }
944
945 ListBase anim_data = {nullptr, nullptr};
946
947 /* Get F-Curves to take keyframes from. */
950 ac, &anim_data, filter, ac->data, static_cast<eAnimCont_Types>(ac->datatype));
951
952 /* Loop through each F-Curve, grabbing the keyframes. */
953 LISTBASE_FOREACH (const bAnimListElem *, ale, &anim_data) {
954 /* Why not use all #eAnim_KeyType here?
955 * All of the other key types are actually "summaries" themselves,
956 * and will just end up duplicating stuff that comes up through
957 * standard filtering of just F-Curves. Given the way that these work,
958 * there isn't really any benefit at all from including them. - Aligorith */
959 switch (ale->datatype) {
960 case ALE_FCURVE:
962 ale->adt, static_cast<FCurve *>(ale->data), keylist, saction_flag, range);
963 break;
964 case ALE_MASKLAY:
965 mask_to_keylist(ac->ads, static_cast<MaskLayer *>(ale->data), keylist);
966 break;
967 case ALE_GPFRAME:
968 gpl_to_keylist(ac->ads, static_cast<bGPDlayer *>(ale->data), keylist);
969 break;
972 ale->adt, static_cast<const GreasePencilLayer *>(ale->data), keylist, saction_flag);
973 break;
974 default:
975 break;
976 }
977 }
978
979 ANIM_animdata_freelist(&anim_data);
980}
981
983 Scene *sce,
984 AnimKeylist *keylist,
985 const int saction_flag,
986 blender::float2 range)
987{
988 bAnimContext ac = {nullptr};
989 ListBase anim_data = {nullptr, nullptr};
990
991 bAnimListElem dummy_chan = {nullptr};
992
993 if (sce == nullptr) {
994 return;
995 }
996
997 /* Create a dummy wrapper data to work with. */
998 dummy_chan.type = ANIMTYPE_SCENE;
999 dummy_chan.data = sce;
1000 dummy_chan.id = &sce->id;
1001 dummy_chan.adt = sce->adt;
1002
1003 ac.ads = ads;
1004 ac.data = &dummy_chan;
1006
1007 /* Get F-Curves to take keyframes from. */
1009
1011 &ac, &anim_data, filter, ac.data, static_cast<eAnimCont_Types>(ac.datatype));
1012
1013 /* Loop through each F-Curve, grabbing the keyframes. */
1014 LISTBASE_FOREACH (const bAnimListElem *, ale, &anim_data) {
1015 fcurve_to_keylist(ale->adt, static_cast<FCurve *>(ale->data), keylist, saction_flag, range);
1016 }
1017
1018 ANIM_animdata_freelist(&anim_data);
1019}
1020
1022 Object *ob,
1023 AnimKeylist *keylist,
1024 const int saction_flag,
1025 blender::float2 range)
1026{
1027 bAnimContext ac = {nullptr};
1028 ListBase anim_data = {nullptr, nullptr};
1029
1030 bAnimListElem dummy_chan = {nullptr};
1031 Base dummy_base = {nullptr};
1032
1033 if (ob == nullptr) {
1034 return;
1035 }
1036
1037 /* Create a dummy wrapper data to work with. */
1038 dummy_base.object = ob;
1039
1040 dummy_chan.type = ANIMTYPE_OBJECT;
1041 dummy_chan.data = &dummy_base;
1042 dummy_chan.id = &ob->id;
1043 dummy_chan.adt = ob->adt;
1044
1045 ac.ads = ads;
1046 ac.data = &dummy_chan;
1048
1049 /* Get F-Curves to take keyframes from. */
1052 &ac, &anim_data, filter, ac.data, static_cast<eAnimCont_Types>(ac.datatype));
1053
1054 /* Loop through each F-Curve, grabbing the keyframes. */
1055 LISTBASE_FOREACH (const bAnimListElem *, ale, &anim_data) {
1056 fcurve_to_keylist(ale->adt, static_cast<FCurve *>(ale->data), keylist, saction_flag, range);
1057 }
1058
1059 ANIM_animdata_freelist(&anim_data);
1060}
1061
1063 CacheFile *cache_file,
1064 AnimKeylist *keylist,
1065 const int saction_flag)
1066{
1067 if (cache_file == nullptr) {
1068 return;
1069 }
1070
1071 /* Create a dummy wrapper data to work with. */
1072 bAnimListElem dummy_chan = {nullptr};
1073 dummy_chan.type = ANIMTYPE_DSCACHEFILE;
1074 dummy_chan.data = cache_file;
1075 dummy_chan.id = &cache_file->id;
1076 dummy_chan.adt = cache_file->adt;
1077
1078 bAnimContext ac = {nullptr};
1079 ac.ads = ads;
1080 ac.data = &dummy_chan;
1082
1083 /* Get F-Curves to take keyframes from. */
1084 ListBase anim_data = {nullptr, nullptr};
1087 &ac, &anim_data, filter, ac.data, static_cast<eAnimCont_Types>(ac.datatype));
1088
1089 /* Loop through each F-Curve, grabbing the keyframes. */
1090 LISTBASE_FOREACH (const bAnimListElem *, ale, &anim_data) {
1092 ale->adt, static_cast<FCurve *>(ale->data), keylist, saction_flag, {-FLT_MAX, FLT_MAX});
1093 }
1094
1095 ANIM_animdata_freelist(&anim_data);
1096}
1097
1098static inline void set_up_beztriple_chain(BezTripleChain &chain,
1099 const FCurve *fcu,
1100 const int key_index,
1101 const bool do_extremes,
1102 const bool is_cyclic)
1103{
1104 chain.cur = &fcu->bezt[key_index];
1105
1106 /* Neighbor columns, accounting for being cyclic. */
1107 if (do_extremes) {
1108 chain.prev = (key_index > 0) ? &fcu->bezt[key_index - 1] :
1109 is_cyclic ? &fcu->bezt[fcu->totvert - 2] :
1110 nullptr;
1111 chain.next = (key_index + 1 < fcu->totvert) ? &fcu->bezt[key_index + 1] :
1112 is_cyclic ? &fcu->bezt[1] :
1113 nullptr;
1114 }
1115}
1116
1118 FCurve *fcu,
1119 AnimKeylist *keylist,
1120 const int saction_flag,
1121 blender::float2 range)
1122{
1123 if (!fcu || fcu->totvert == 0 || !fcu->bezt) {
1124 return;
1125 }
1127
1128 if (adt) {
1129 ANIM_nla_mapping_apply_fcurve(adt, fcu, false, false);
1130 }
1131
1132 const bool is_cyclic = BKE_fcurve_is_cyclic(fcu) && (fcu->totvert >= 2);
1133 const bool do_extremes = (saction_flag & SACTION_SHOW_EXTREMES) != 0;
1134
1135 BezTripleChain chain = {nullptr};
1136 /* The indices for which keys have been added to the key columns. Initialized as invalid bounds
1137 * for the case that no keyframes get added to the key-columns, which happens when the given
1138 * range doesn't overlap with the existing keyframes. */
1139 blender::Bounds<int> index_bounds(int(fcu->totvert), 0);
1140 /* The following is used to find the keys that are JUST outside the range. This is done so
1141 * drawing in the dope sheet can create lines that extend off-screen. */
1142 float left_outside_key_x = -FLT_MAX;
1143 float right_outside_key_x = FLT_MAX;
1144 int left_outside_key_index = -1;
1145 int right_outside_key_index = -1;
1146 /* Loop through beztriples, making ActKeysColumns. */
1147 for (int v = 0; v < fcu->totvert; v++) {
1148 /* Not using binary search to limit the range because the FCurve might not be sorted e.g. when
1149 * transforming in the Dope Sheet. */
1150 const float x = fcu->bezt[v].vec[1][0];
1151 if (x < range[0] && x > left_outside_key_x) {
1152 left_outside_key_x = x;
1153 left_outside_key_index = v;
1154 }
1155 if (x > range[1] && x < right_outside_key_x) {
1156 right_outside_key_x = x;
1157 right_outside_key_index = v;
1158 }
1159 if (x < range[0] || x > range[1]) {
1160 continue;
1161 }
1162 blender::math::min_max(v, index_bounds.min, index_bounds.max);
1163 set_up_beztriple_chain(chain, fcu, v, do_extremes, is_cyclic);
1164
1165 add_bezt_to_keycolumns_list(keylist, &chain);
1166 }
1167
1168 if (left_outside_key_index >= 0) {
1169 set_up_beztriple_chain(chain, fcu, left_outside_key_index, do_extremes, is_cyclic);
1170 add_bezt_to_keycolumns_list(keylist, &chain);
1171 /* Checking min and max because the FCurve might not be sorted. */
1172 index_bounds.min = blender::math::min(index_bounds.min, left_outside_key_index);
1173 index_bounds.max = blender::math::max(index_bounds.max, left_outside_key_index);
1174 }
1175 if (right_outside_key_index >= 0) {
1176 set_up_beztriple_chain(chain, fcu, right_outside_key_index, do_extremes, is_cyclic);
1177 add_bezt_to_keycolumns_list(keylist, &chain);
1178 index_bounds.min = blender::math::min(index_bounds.min, right_outside_key_index);
1179 index_bounds.max = blender::math::max(index_bounds.max, right_outside_key_index);
1180 }
1181 /* Not using index_bounds.is_empty() because that returns true if min and max are the same. That
1182 * is a valid configuration in this case though. */
1183 if (index_bounds.min <= index_bounds.max) {
1185 keylist, &fcu->bezt[index_bounds.min], (index_bounds.max + 1) - index_bounds.min);
1186 }
1187
1188 if (adt) {
1189 ANIM_nla_mapping_apply_fcurve(adt, fcu, true, false);
1190 }
1191}
1192
1194 bActionGroup *agrp,
1195 AnimKeylist *keylist,
1196 const int saction_flag,
1197 blender::float2 range)
1198{
1199 if (!agrp) {
1200 return;
1201 }
1202
1203 /* Legacy actions. */
1204 if (agrp->wrap().is_legacy()) {
1205 LISTBASE_FOREACH (FCurve *, fcu, &agrp->channels) {
1206 if (fcu->grp != agrp) {
1207 break;
1208 }
1209 fcurve_to_keylist(adt, fcu, keylist, saction_flag, range);
1210 }
1211 return;
1212 }
1213
1214 /* Layered actions. */
1215 animrig::ChannelBag &channel_bag = agrp->channel_bag->wrap();
1216 Span<FCurve *> fcurves = channel_bag.fcurves().slice(agrp->fcurve_range_start,
1217 agrp->fcurve_range_length);
1218 for (FCurve *fcurve : fcurves) {
1219 fcurve_to_keylist(adt, fcurve, keylist, saction_flag, range);
1220 }
1221}
1222
1224 animrig::Action &action,
1225 const animrig::slot_handle_t slot_handle,
1226 AnimKeylist *keylist,
1227 const int saction_flag,
1228 blender::float2 range)
1229{
1230 BLI_assert(GS(action.id.name) == ID_AC);
1231 for (FCurve *fcurve : fcurves_for_action_slot(action, slot_handle)) {
1232 fcurve_to_keylist(adt, fcurve, keylist, saction_flag, range);
1233 }
1234}
1235
1237 bAction *dna_action,
1238 AnimKeylist *keylist,
1239 const int saction_flag,
1240 blender::float2 range)
1241{
1242 if (!dna_action) {
1243 return;
1244 }
1245
1246 blender::animrig::Action &action = dna_action->wrap();
1247
1248 /* TODO: move this into fcurves_for_action_slot(). */
1249 if (action.is_action_legacy()) {
1250 LISTBASE_FOREACH (FCurve *, fcu, &action.curves) {
1251 fcurve_to_keylist(adt, fcu, keylist, saction_flag, range);
1252 }
1253 return;
1254 }
1255
1260 action_slot_to_keylist(adt, action, adt->slot_handle, keylist, saction_flag, range);
1261}
1262
1263void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, AnimKeylist *keylist, const bool active)
1264{
1265 if (!gpd || !keylist) {
1266 return;
1267 }
1268
1269 /* For now, just aggregate out all the frames, but only for visible layers. */
1271 if (gpl->flag & GP_LAYER_HIDE) {
1272 continue;
1273 }
1274 if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) {
1275 gpl_to_keylist(ads, gpl, keylist);
1276 }
1277 }
1278}
1279
1281 const GreasePencil *grease_pencil,
1282 AnimKeylist *keylist,
1283 const int saction_flag,
1284 const bool active_layer_only)
1285{
1286 if ((grease_pencil == nullptr) || (keylist == nullptr)) {
1287 return;
1288 }
1289
1290 if (active_layer_only && grease_pencil->has_active_layer()) {
1291 grease_pencil_cels_to_keylist(adt, grease_pencil->get_active_layer(), keylist, saction_flag);
1292 return;
1293 }
1294
1295 for (const blender::bke::greasepencil::Layer *layer : grease_pencil->layers()) {
1296 grease_pencil_cels_to_keylist(adt, layer, keylist, saction_flag);
1297 }
1298}
1299
1301 const GreasePencilLayer *gpl,
1302 AnimKeylist *keylist,
1303 int /*saction_flag*/)
1304{
1305 using namespace blender::bke::greasepencil;
1306 const Layer &layer = gpl->wrap();
1307 for (auto item : layer.frames().items()) {
1308 GreasePencilCel cel{};
1309 cel.frame_number = item.key;
1310 cel.frame = item.value;
1311
1312 float cfra = float(item.key);
1314 keylist, cfra, nalloc_ak_cel, nupdate_ak_cel, static_cast<void *>(&cel));
1315 }
1316}
1317
1319 const GreasePencilLayerTreeGroup *layer_group,
1320 AnimKeylist *keylist,
1321 const int saction_flag)
1322{
1323 if ((layer_group == nullptr) || (keylist == nullptr)) {
1324 return;
1325 }
1326
1328 const blender::bke::greasepencil::TreeNode &node = node_->wrap();
1329 if (node.is_group()) {
1330 grease_pencil_layer_group_to_keylist(adt, &node.as_group(), keylist, saction_flag);
1331 }
1332 else if (node.is_layer()) {
1333 grease_pencil_cels_to_keylist(adt, &node.as_layer(), keylist, saction_flag);
1334 }
1335 }
1336}
1337
1338void gpl_to_keylist(bDopeSheet * /*ads*/, bGPDlayer *gpl, AnimKeylist *keylist)
1339{
1340 if (!gpl || !keylist) {
1341 return;
1342 }
1343
1345 /* Although the frames should already be in an ordered list,
1346 * they are not suitable for displaying yet. */
1347 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
1348 add_gpframe_to_keycolumns_list(keylist, gpf);
1349 }
1350
1351 update_keyblocks(keylist, nullptr, 0);
1352}
1353
1354void mask_to_keylist(bDopeSheet * /*ads*/, MaskLayer *masklay, AnimKeylist *keylist)
1355{
1356 if (!masklay || !keylist) {
1357 return;
1358 }
1360 LISTBASE_FOREACH (MaskLayerShape *, masklay_shape, &masklay->splines_shapes) {
1361 add_masklay_to_keycolumns_list(keylist, masklay_shape);
1362 }
1363
1364 update_keyblocks(keylist, nullptr, 0);
1365}
Functions and classes to work with Actions.
bool BKE_fcurve_is_cyclic(const FCurve *fcu)
#define BEZT_BINARYSEARCH_THRESH
Low-level operations for grease pencil.
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define BLI_INLINE
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:90
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:331
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:370
#define ELEM(...)
#define IS_EQF(a, b)
#define IS_EQT(a, b, c)
@ ID_AC
@ SACTION_SHOW_EXTREMES
#define BEZT_ISSEL_ANY(bezt)
@ HD_AUTO_ANIM
@ HD_VECT
@ HD_FREE
@ HD_AUTO
#define BEZKEYTYPE(bezt)
@ BEZT_IPO_ELASTIC
@ BEZT_IPO_BEZ
eBezTriple_KeyframeType
@ BEZT_KEYTYPE_MOVEHOLD
@ BEZT_KEYTYPE_KEYFRAME
@ MASK_SHAPE_SELECT
Object is a sort of wrapper for general info.
@ ANIMTYPE_SCENE
@ ANIMTYPE_DSCACHEFILE
@ ANIMTYPE_OBJECT
@ ALE_GREASE_PENCIL_CEL
@ ALE_GPFRAME
@ ALE_FCURVE
@ ALE_MASKLAY
eAnimCont_Types
@ ANIMCONT_CHANNEL
eAnimFilter_Flags
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_FCURVESONLY
@ ACTKEYBLOCK_FLAG_ANY_HOLD
@ ACTKEYBLOCK_FLAG_MOVING_HOLD
@ ACTKEYBLOCK_FLAG_GPENCIL
@ ACTKEYBLOCK_FLAG_NON_BEZIER
@ ACTKEYBLOCK_FLAG_STATIC_HOLD
eKeyframeHandleDrawOpts
@ KEYFRAME_HANDLE_VECTOR
@ KEYFRAME_HANDLE_FREE
@ KEYFRAME_HANDLE_AUTO_CLAMP
@ KEYFRAME_HANDLE_AUTO
@ KEYFRAME_HANDLE_ALIGNED
eKeyframeExtremeDrawOpts
@ KEYFRAME_EXTREME_MAX
@ KEYFRAME_EXTREME_MIXED
@ KEYFRAME_EXTREME_NONE
@ KEYFRAME_EXTREME_FLAT
@ KEYFRAME_EXTREME_MIN
Read Guarded memory(de)allocation.
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:457
void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, bool only_keys)
Definition anim_draw.cc:290
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, const eAnimFilter_Flags filter_mode, void *data, const eAnimCont_Types datatype)
ATTR_WARN_UNUSED_RESULT const BMVert * v
blender::Span< const FCurve * > fcurves() const
local_group_size(16, 16) .push_constant(Type b
#define SELECT
static bool is_cyclic(const Nurb *nu)
draw_view in_light_buf[] float
uint col
#define GS(x)
Definition iris.cc:202
BLI_INLINE bool is_cfra_lt(const float a, const float b)
static ActKeyColumn * ED_keylist_find_neighbor_front_to_back(ActKeyColumn *cursor, float cfra)
void mask_to_keylist(bDopeSheet *, MaskLayer *masklay, AnimKeylist *keylist)
BLI_INLINE bool is_cfra_eq(const float a, const float b)
static void keylist_first_last(const AnimKeylist *keylist, const ActKeyColumn **first_column, const ActKeyColumn **last_column)
const ActKeyColumn * ED_keylist_find_prev(const AnimKeylist *keylist, const float cfra)
static eKeyframeHandleDrawOpts bezt_handle_type(const BezTriple *bezt)
static ActKeyColumn * nalloc_ak_cel(void *data)
bool actkeyblock_is_valid(const ActKeyColumn *ac)
static void nupdate_ak_gpframe(ActKeyColumn *ak, void *data)
bool ED_keylist_selected_keys_frame_range(const AnimKeylist *keylist, Range2f *r_frame_range)
std::function< ActKeyColumn *(void *userdata)> KeylistCreateColumnFunction
std::function< void(ActKeyColumn *, void *)> KeylistUpdateColumnFunction
void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, AnimKeylist *keylist, const bool active)
static ActKeyColumn * nalloc_ak_masklayshape(void *data)
static void ED_keylist_reset_last_accessed(AnimKeylist *keylist)
static void nupdate_ak_cel(ActKeyColumn *ak, void *data)
static void nupdate_ak_masklayshape(ActKeyColumn *ak, void *data)
void scene_to_keylist(bDopeSheet *ads, Scene *sce, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
static ActKeyColumn * nalloc_ak_gpframe(void *data)
static void ED_keylist_runtime_init_listbase(AnimKeylist *keylist)
const ActKeyColumn * ED_keylist_find_any_between(const AnimKeylist *keylist, const Range2f frame_range)
static void add_gpframe_to_keycolumns_list(AnimKeylist *keylist, bGPDframe *gpf)
static void ED_keylist_runtime_init(AnimKeylist *keylist)
void ob_to_keylist(bDopeSheet *ads, Object *ob, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
void cachefile_to_keylist(bDopeSheet *ads, CacheFile *cache_file, AnimKeylist *keylist, const int saction_flag)
void grease_pencil_data_block_to_keylist(AnimData *adt, const GreasePencil *grease_pencil, AnimKeylist *keylist, const int saction_flag, const bool active_layer_only)
static void nupdate_ak_bezt(ActKeyColumn *ak, void *data)
void ED_keylist_prepare_for_direct_access(AnimKeylist *keylist)
void summary_to_keylist(bAnimContext *ac, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
bool ED_keylist_all_keys_frame_range(const AnimKeylist *keylist, Range2f *r_frame_range)
static void compute_keyblock_data(ActKeyBlockInfo *info, const BezTriple *prev, const BezTriple *beztn)
static void add_keyblock_info(ActKeyColumn *col, const ActKeyBlockInfo *block)
AnimKeylist * ED_keylist_create()
static const ActKeyBlockInfo dummy_keyblock
int actkeyblock_get_valid_hold(const ActKeyColumn *ac)
static void set_up_beztriple_chain(BezTripleChain &chain, const FCurve *fcu, const int key_index, const bool do_extremes, const bool is_cyclic)
void ED_keylist_free(AnimKeylist *keylist)
void fcurve_to_keylist(AnimData *adt, FCurve *fcu, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
static eKeyframeExtremeDrawOpts bezt_extreme_type(const BezTripleChain *chain)
static ActKeyColumn * nalloc_ak_bezt(void *data)
static void ED_keylist_convert_key_columns_to_array(AnimKeylist *keylist)
static void ED_keylist_add_or_update_column(AnimKeylist *keylist, float cfra, KeylistCreateColumnFunction create_func, KeylistUpdateColumnFunction update_func, void *userdata)
static void add_bezt_to_keyblocks_list(AnimKeylist *keylist, BezTriple *bezt, const int bezt_len)
static void update_keyblocks(AnimKeylist *keylist, BezTriple *bezt, const int bezt_len)
static void add_masklay_to_keycolumns_list(AnimKeylist *keylist, MaskLayerShape *masklay_shape)
void action_slot_to_keylist(AnimData *adt, animrig::Action &action, const animrig::slot_handle_t slot_handle, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
const ActKeyColumn * ED_keylist_find_next(const AnimKeylist *keylist, const float cfra)
static void ED_keylist_runtime_update_key_column_next_prev(AnimKeylist *keylist)
int64_t ED_keylist_array_len(const AnimKeylist *keylist)
const ListBase * ED_keylist_listbase(const AnimKeylist *keylist)
static const ActKeyColumn * ED_keylist_find_upper_bound(const AnimKeylist *keylist, const float cfra)
bool ED_keylist_is_empty(const AnimKeylist *keylist)
const ActKeyColumn * ED_keylist_find_exact(const AnimKeylist *keylist, const float cfra)
static ActKeyColumn * ED_keylist_find_neighbor_back_to_front(ActKeyColumn *cursor, float cfra)
void grease_pencil_layer_group_to_keylist(AnimData *adt, const GreasePencilLayerTreeGroup *layer_group, AnimKeylist *keylist, const int saction_flag)
static const ActKeyColumn * ED_keylist_find_lower_bound(const AnimKeylist *keylist, const float cfra)
static void add_bezt_to_keycolumns_list(AnimKeylist *keylist, BezTripleChain *bezt)
void action_to_keylist(AnimData *adt, bAction *dna_action, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
void grease_pencil_cels_to_keylist(AnimData *, const GreasePencilLayer *gpl, AnimKeylist *keylist, int)
void gpl_to_keylist(bDopeSheet *, bGPDlayer *gpl, AnimKeylist *keylist)
void action_group_to_keylist(AnimData *adt, bActionGroup *agrp, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
static ActKeyColumn * ED_keylist_find_exact_or_neighbor_column(AnimKeylist *keylist, float cfra)
const ActKeyColumn * ED_keylist_array(const AnimKeylist *keylist)
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
decltype(::ActionSlot::handle) slot_handle_t
T min(const T &a, const T &b)
void min_max(const T &value, T &min, T &max)
T max(const T &a, const T &b)
static PyObject * create_func(PyObject *, PyObject *args)
Definition python.cpp:161
#define FLT_MAX
Definition stdcycles.h:14
__int64 int64_t
Definition stdint.h:89
eBezTriple_KeyframeType key_type
ActKeyColumn * prev
ActKeyColumn * next
ActKeyBlockInfo block
int32_t slot_handle
ListBase list_wrapper
std::optional< ActKeyColumn * > last_accessed_column
struct AnimKeylist::@302 runtime
blender::Array< ActKeyColumn > key_columns
struct Object * object
float vec[3][3]
struct AnimData * adt
BezTriple * bezt
unsigned int totvert
GreasePencilFrame frame
char name[66]
Definition DNA_ID.h:425
void * last
void * first
ListBase splines_shapes
struct AnimData * adt
float min
Definition BLI_range.h:16
float max
Definition BLI_range.h:17
struct AnimData * adt
struct ActionChannelBag * channel_bag
ListBase curves
eAnimCont_Types datatype
bDopeSheet * ads
AnimData * adt
eAnim_ChannelType type