Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen Bakker <jeroen@blender.org>2021-07-19 16:53:04 +0300
committerJeroen Bakker <jeroen@blender.org>2021-07-19 16:53:04 +0300
commit132522cba894954406877eba9067b9be06c60cde (patch)
tree54089c726d3b2517637b1749dc841a23c148987f /source/blender
parentceb612a79c7c49967fe6976c261ad3f9fa47adfb (diff)
Cleanup: Separate keyframes_draw and keyframes_keylist.
The keylist functions are used in other places for none drawing related stuff. Fe pose_slide uses it.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/editors/animation/CMakeLists.txt1
-rw-r--r--source/blender/editors/animation/anim_draw.c1
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c2
-rw-r--r--source/blender/editors/animation/keyframes_draw.c758
-rw-r--r--source/blender/editors/animation/keyframes_keylist.c793
-rw-r--r--source/blender/editors/armature/pose_lib.c2
-rw-r--r--source/blender/editors/armature/pose_slide.c2
-rw-r--r--source/blender/editors/include/ED_keyframes_draw.h146
-rw-r--r--source/blender/editors/include/ED_keyframes_keylist.h195
-rw-r--r--source/blender/editors/interface/interface_icons.c1
-rw-r--r--source/blender/editors/screen/screen_ops.c2
-rw-r--r--source/blender/editors/space_action/action_select.c2
-rw-r--r--source/blender/editors/space_nla/nla_draw.c1
13 files changed, 998 insertions, 908 deletions
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt
index f50a5ffbb5e..7a53b54b5a4 100644
--- a/source/blender/editors/animation/CMakeLists.txt
+++ b/source/blender/editors/animation/CMakeLists.txt
@@ -47,6 +47,7 @@ set(SRC
keyframes_draw.c
keyframes_edit.c
keyframes_general.c
+ keyframes_keylist.c
keyframing.c
keyingsets.c
time_scrub_ui.c
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 2fcd59a1bbe..baf8adf28d0 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -48,6 +48,7 @@
#include "ED_anim_api.h"
#include "ED_keyframes_draw.h"
#include "ED_keyframes_edit.h"
+#include "ED_keyframes_keylist.h"
#include "RNA_access.h"
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index 51a897600e1..bddd5dbff55 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -43,7 +43,7 @@
#include "GPU_vertex_buffer.h"
#include "ED_anim_api.h"
-#include "ED_keyframes_draw.h"
+#include "ED_keyframes_keylist.h"
#include "CLG_log.h"
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 06107b6fee6..4f512c9d7ca 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -24,28 +24,17 @@
/* System includes ----------------------------------------------------- */
#include <float.h>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
#include "BLI_dlrbTree.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_rect.h"
-#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_cachefile_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_mask_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "BKE_fcurve.h"
-
#include "GPU_immediate.h"
#include "GPU_state.h"
@@ -55,498 +44,7 @@
#include "ED_anim_api.h"
#include "ED_keyframes_draw.h"
-
-/* *************************** Keyframe Processing *************************** */
-
-/* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
-
-BLI_INLINE bool is_cfra_eq(float a, float b)
-{
- return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH);
-}
-
-BLI_INLINE bool is_cfra_lt(float a, float b)
-{
- return (b - a) > BEZT_BINARYSEARCH_THRESH;
-}
-
-/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
-/* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */
-short compare_ak_cfraPtr(void *node, void *data)
-{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- const float *cframe = data;
- float val = *cframe;
-
- if (is_cfra_eq(val, ak->cfra)) {
- return 0;
- }
-
- if (val < ak->cfra) {
- return -1;
- }
- return 1;
-}
-
-/* --------------- */
-
-/* Set of references to three logically adjacent keys. */
-typedef struct BezTripleChain {
- /* Current keyframe. */
- BezTriple *cur;
-
- /* Logical neighbors. May be NULL. */
- BezTriple *prev, *next;
-} BezTripleChain;
-
-/* Categorize the interpolation & handle type of the keyframe. */
-static eKeyframeHandleDrawOpts bezt_handle_type(BezTriple *bezt)
-{
- if (bezt->h1 == HD_AUTO_ANIM && bezt->h2 == HD_AUTO_ANIM) {
- return KEYFRAME_HANDLE_AUTO_CLAMP;
- }
- if (ELEM(bezt->h1, HD_AUTO_ANIM, HD_AUTO) && ELEM(bezt->h2, HD_AUTO_ANIM, HD_AUTO)) {
- return KEYFRAME_HANDLE_AUTO;
- }
- if (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) {
- return KEYFRAME_HANDLE_VECTOR;
- }
- if (ELEM(HD_FREE, bezt->h1, bezt->h2)) {
- return KEYFRAME_HANDLE_FREE;
- }
- return KEYFRAME_HANDLE_ALIGNED;
-}
-
-/* Determine if the keyframe is an extreme by comparing with neighbors.
- * Ends of fixed-value sections and of the whole curve are also marked.
- */
-static eKeyframeExtremeDrawOpts bezt_extreme_type(BezTripleChain *chain)
-{
- if (chain->prev == NULL && chain->next == NULL) {
- return KEYFRAME_EXTREME_NONE;
- }
-
- /* Keyframe values for the current one and neighbors. */
- float cur_y = chain->cur->vec[1][1];
- float prev_y = cur_y, next_y = cur_y;
-
- if (chain->prev && !IS_EQF(cur_y, chain->prev->vec[1][1])) {
- prev_y = chain->prev->vec[1][1];
- }
- if (chain->next && !IS_EQF(cur_y, chain->next->vec[1][1])) {
- next_y = chain->next->vec[1][1];
- }
-
- /* Static hold. */
- if (prev_y == cur_y && next_y == cur_y) {
- return KEYFRAME_EXTREME_FLAT;
- }
-
- /* Middle of an incline. */
- if ((prev_y < cur_y && next_y > cur_y) || (prev_y > cur_y && next_y < cur_y)) {
- return KEYFRAME_EXTREME_NONE;
- }
-
- /* Bezier handle values for the overshoot check. */
- bool l_bezier = chain->prev && chain->prev->ipo == BEZT_IPO_BEZ;
- bool r_bezier = chain->next && chain->cur->ipo == BEZT_IPO_BEZ;
- float handle_l = l_bezier ? chain->cur->vec[0][1] : cur_y;
- float handle_r = r_bezier ? chain->cur->vec[2][1] : cur_y;
-
- /* Detect extremes. One of the neighbors is allowed to be equal to current. */
- if (prev_y < cur_y || next_y < cur_y) {
- bool is_overshoot = (handle_l > cur_y || handle_r > cur_y);
-
- return KEYFRAME_EXTREME_MAX | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0);
- }
-
- if (prev_y > cur_y || next_y > cur_y) {
- bool is_overshoot = (handle_l < cur_y || handle_r < cur_y);
-
- return KEYFRAME_EXTREME_MIN | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0);
- }
-
- return KEYFRAME_EXTREME_NONE;
-}
-
-/* Comparator callback used for ActKeyColumns and BezTripleChain */
-static short compare_ak_bezt(void *node, void *data)
-{
- BezTripleChain *chain = data;
-
- return compare_ak_cfraPtr(node, &chain->cur->vec[1][0]);
-}
-
-/* New node callback used for building ActKeyColumns from BezTripleChain */
-static DLRBT_Node *nalloc_ak_bezt(void *data)
-{
- ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
- BezTripleChain *chain = data;
- BezTriple *bezt = chain->cur;
-
- /* store settings based on state of BezTriple */
- ak->cfra = bezt->vec[1][0];
- ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0;
- ak->key_type = BEZKEYTYPE(bezt);
- ak->handle_type = bezt_handle_type(bezt);
- ak->extreme_type = bezt_extreme_type(chain);
-
- /* count keyframes in this column */
- ak->totkey = 1;
-
- return (DLRBT_Node *)ak;
-}
-
-/* Node updater callback used for building ActKeyColumns from BezTripleChain */
-static void nupdate_ak_bezt(void *node, void *data)
-{
- ActKeyColumn *ak = node;
- BezTripleChain *chain = data;
- BezTriple *bezt = chain->cur;
-
- /* set selection status and 'touched' status */
- if (BEZT_ISSEL_ANY(bezt)) {
- ak->sel = SELECT;
- }
-
- /* count keyframes in this column */
- ak->totkey++;
-
- /* For keyframe type, 'proper' keyframes have priority over breakdowns
- * (and other types for now). */
- if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME) {
- ak->key_type = BEZT_KEYTYPE_KEYFRAME;
- }
-
- /* For interpolation type, select the highest value (enum is sorted). */
- ak->handle_type = MAX2(ak->handle_type, bezt_handle_type(bezt));
-
- /* For extremes, detect when combining different states. */
- char new_extreme = bezt_extreme_type(chain);
-
- if (new_extreme != ak->extreme_type) {
- /* Replace the flat status without adding mixed. */
- if (ak->extreme_type == KEYFRAME_EXTREME_FLAT) {
- ak->extreme_type = new_extreme;
- }
- else if (new_extreme != KEYFRAME_EXTREME_FLAT) {
- ak->extreme_type |= (new_extreme | KEYFRAME_EXTREME_MIXED);
- }
- }
-}
-
-/* ......... */
-
-/* Comparator callback used for ActKeyColumns and GPencil frame */
-static short compare_ak_gpframe(void *node, void *data)
-{
- bGPDframe *gpf = (bGPDframe *)data;
-
- float frame = gpf->framenum;
- return compare_ak_cfraPtr(node, &frame);
-}
-
-/* New node callback used for building ActKeyColumns from GPencil frames */
-static DLRBT_Node *nalloc_ak_gpframe(void *data)
-{
- ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF");
- bGPDframe *gpf = (bGPDframe *)data;
-
- /* store settings based on state of BezTriple */
- ak->cfra = gpf->framenum;
- ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0;
- ak->key_type = gpf->key_type;
-
- /* count keyframes in this column */
- ak->totkey = 1;
- /* Set as visible block. */
- ak->totblock = 1;
- ak->block.sel = ak->sel;
- ak->block.flag |= ACTKEYBLOCK_FLAG_GPENCIL;
-
- return (DLRBT_Node *)ak;
-}
-
-/* Node updater callback used for building ActKeyColumns from GPencil frames */
-static void nupdate_ak_gpframe(void *node, void *data)
-{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- bGPDframe *gpf = (bGPDframe *)data;
-
- /* set selection status and 'touched' status */
- if (gpf->flag & GP_FRAME_SELECT) {
- ak->sel = SELECT;
- }
-
- /* count keyframes in this column */
- ak->totkey++;
-
- /* for keyframe type, 'proper' keyframes have priority over breakdowns
- * (and other types for now). */
- if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME) {
- ak->key_type = BEZT_KEYTYPE_KEYFRAME;
- }
-}
-
-/* ......... */
-
-/* Comparator callback used for ActKeyColumns and GPencil frame */
-static short compare_ak_masklayshape(void *node, void *data)
-{
- MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
-
- float frame = masklay_shape->frame;
- return compare_ak_cfraPtr(node, &frame);
-}
-
-/* New node callback used for building ActKeyColumns from GPencil frames */
-static DLRBT_Node *nalloc_ak_masklayshape(void *data)
-{
- ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF");
- MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
-
- /* store settings based on state of BezTriple */
- ak->cfra = masklay_shape->frame;
- ak->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? SELECT : 0;
-
- /* count keyframes in this column */
- ak->totkey = 1;
-
- return (DLRBT_Node *)ak;
-}
-
-/* Node updater callback used for building ActKeyColumns from GPencil frames */
-static void nupdate_ak_masklayshape(void *node, void *data)
-{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
-
- /* set selection status and 'touched' status */
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
- ak->sel = SELECT;
- }
-
- /* count keyframes in this column */
- ak->totkey++;
-}
-
-/* --------------- */
-
-/* Add the given BezTriple to the given 'list' of Keyframes */
-static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTripleChain *bezt)
-{
- if (ELEM(NULL, keys, bezt)) {
- return;
- }
-
- BLI_dlrbTree_add(keys, compare_ak_bezt, nalloc_ak_bezt, nupdate_ak_bezt, bezt);
-}
-
-/* Add the given GPencil Frame to the given 'list' of Keyframes */
-static void add_gpframe_to_keycolumns_list(DLRBT_Tree *keys, bGPDframe *gpf)
-{
- if (ELEM(NULL, keys, gpf)) {
- return;
- }
-
- BLI_dlrbTree_add(keys, compare_ak_gpframe, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf);
-}
-
-/* Add the given MaskLayerShape Frame to the given 'list' of Keyframes */
-static void add_masklay_to_keycolumns_list(DLRBT_Tree *keys, MaskLayerShape *masklay_shape)
-{
- if (ELEM(NULL, keys, masklay_shape)) {
- return;
- }
-
- BLI_dlrbTree_add(keys,
- compare_ak_masklayshape,
- nalloc_ak_masklayshape,
- nupdate_ak_masklayshape,
- masklay_shape);
-}
-
-/* ActKeyBlocks (Long Keyframes) ------------------------------------------ */
-
-static const ActKeyBlockInfo dummy_keyblock = {0};
-
-static void compute_keyblock_data(ActKeyBlockInfo *info, BezTriple *prev, BezTriple *beztn)
-{
- memset(info, 0, sizeof(ActKeyBlockInfo));
-
- if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) {
- /* Animator tagged a "moving hold"
- * - Previous key must also be tagged as a moving hold, otherwise
- * we're just dealing with the first of a pair, and we don't
- * want to be creating any phantom holds...
- */
- if (BEZKEYTYPE(prev) == BEZT_KEYTYPE_MOVEHOLD) {
- info->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
- }
- }
-
- /* Check for same values...
- * - Handles must have same central value as each other
- * - Handles which control that section of the curve must be constant
- */
- if (IS_EQF(beztn->vec[1][1], prev->vec[1][1])) {
- bool hold;
-
- /* Only check handles in case of actual bezier interpolation. */
- if (prev->ipo == BEZT_IPO_BEZ) {
- hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) &&
- IS_EQF(prev->vec[1][1], prev->vec[2][1]);
- }
- /* This interpolation type induces movement even between identical keys. */
- else {
- hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC);
- }
-
- if (hold) {
- info->flag |= ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
- }
- }
-
- /* Remember non-bezier interpolation info. */
- if (prev->ipo != BEZT_IPO_BEZ) {
- info->flag |= ACTKEYBLOCK_FLAG_NON_BEZIER;
- }
-
- info->sel = BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn);
-}
-
-static void add_keyblock_info(ActKeyColumn *col, const ActKeyBlockInfo *block)
-{
- /* New curve and block. */
- if (col->totcurve <= 1 && col->totblock == 0) {
- memcpy(&col->block, block, sizeof(ActKeyBlockInfo));
- }
- /* Existing curve. */
- else {
- col->block.conflict |= (col->block.flag ^ block->flag);
- col->block.flag |= block->flag;
- col->block.sel |= block->sel;
- }
-
- if (block->flag) {
- col->totblock++;
- }
-}
-
-static void add_bezt_to_keyblocks_list(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
-{
- ActKeyColumn *col = keys->first;
-
- if (bezt && bezt_len >= 2) {
- ActKeyBlockInfo block;
-
- /* Find the first key column while inserting dummy blocks. */
- for (; col != NULL && is_cfra_lt(col->cfra, bezt[0].vec[1][0]); col = col->next) {
- add_keyblock_info(col, &dummy_keyblock);
- }
-
- BLI_assert(col != NULL);
-
- /* Insert real blocks. */
- for (int v = 1; col != NULL && v < bezt_len; v++, bezt++) {
- /* Wrong order of bezier keys: resync position. */
- if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) {
- /* Backtrack to find the right location. */
- if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) {
- ActKeyColumn *newcol = (ActKeyColumn *)BLI_dlrbTree_search_exact(
- keys, compare_ak_cfraPtr, &bezt[1].vec[1][0]);
-
- if (newcol != NULL) {
- col = newcol;
-
- /* The previous keyblock is garbage too. */
- if (col->prev != NULL) {
- add_keyblock_info(col->prev, &dummy_keyblock);
- }
- }
- else {
- BLI_assert(false);
- }
- }
-
- continue;
- }
-
- /* Normal sequence */
- BLI_assert(is_cfra_eq(col->cfra, bezt[0].vec[1][0]));
-
- compute_keyblock_data(&block, bezt, bezt + 1);
-
- for (; col != NULL && is_cfra_lt(col->cfra, bezt[1].vec[1][0]); col = col->next) {
- add_keyblock_info(col, &block);
- }
-
- BLI_assert(col != NULL);
- }
- }
-
- /* Insert dummy blocks at the end. */
- for (; col != NULL; col = col->next) {
- add_keyblock_info(col, &dummy_keyblock);
- }
-}
-
-/* Walk through columns and propagate blocks and totcurve.
- *
- * This must be called even by animation sources that don't generate
- * keyblocks to keep the data structure consistent after adding columns.
- */
-static void update_keyblocks(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
-{
- /* Recompute the prev/next linked list. */
- BLI_dlrbTree_linkedlist_sync(keys);
-
- /* Find the curve count */
- int max_curve = 0;
-
- LISTBASE_FOREACH (ActKeyColumn *, col, keys) {
- max_curve = MAX2(max_curve, col->totcurve);
- }
-
- /* Propagate blocks to inserted keys */
- ActKeyColumn *prev_ready = NULL;
-
- LISTBASE_FOREACH (ActKeyColumn *, col, keys) {
- /* Pre-existing column. */
- if (col->totcurve > 0) {
- prev_ready = col;
- }
- /* Newly inserted column, so copy block data from previous. */
- else if (prev_ready != NULL) {
- col->totblock = prev_ready->totblock;
- memcpy(&col->block, &prev_ready->block, sizeof(ActKeyBlockInfo));
- }
-
- col->totcurve = max_curve + 1;
- }
-
- /* Add blocks on top */
- add_bezt_to_keyblocks_list(keys, bezt, bezt_len);
-}
-
-/* --------- */
-
-bool actkeyblock_is_valid(ActKeyColumn *ac)
-{
- return ac != NULL && ac->next != NULL && ac->totblock > 0;
-}
-
-/* Checks if ActKeyBlock should exist... */
-int actkeyblock_get_valid_hold(ActKeyColumn *ac)
-{
- /* check that block is valid */
- if (!actkeyblock_is_valid(ac)) {
- return 0;
- }
-
- const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD);
- return (ac->block.flag & ~ac->block.conflict) & hold_mask;
-}
+#include "ED_keyframes_keylist.h"
/* *************************** Keyframe Drawing *************************** */
@@ -1029,257 +527,3 @@ void draw_masklay_channel(View2D *v2d,
BLI_dlrbTree_free(&keys);
}
-
-/* *************************** Keyframe List Conversions *************************** */
-
-void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, int saction_flag)
-{
- if (ac) {
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- /* get F-Curves to take keyframes from */
- filter = ANIMFILTER_DATA_VISIBLE;
- ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
-
- /* loop through each F-Curve, grabbing the keyframes */
- for (ale = anim_data.first; ale; ale = ale->next) {
- /* Why not use all #eAnim_KeyType here?
- * All of the other key types are actually "summaries" themselves,
- * and will just end up duplicating stuff that comes up through
- * standard filtering of just F-Curves. Given the way that these work,
- * there isn't really any benefit at all from including them. - Aligorith */
-
- switch (ale->datatype) {
- case ALE_FCURVE:
- fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
- break;
- case ALE_MASKLAY:
- mask_to_keylist(ac->ads, ale->data, keys);
- break;
- case ALE_GPFRAME:
- gpl_to_keylist(ac->ads, ale->data, keys);
- break;
- default:
- // printf("%s: datatype %d unhandled\n", __func__, ale->datatype);
- break;
- }
- }
-
- ANIM_animdata_freelist(&anim_data);
- }
-}
-
-void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, int saction_flag)
-{
- bAnimContext ac = {NULL};
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- bAnimListElem dummychan = {NULL};
-
- if (sce == NULL) {
- return;
- }
-
- /* create a dummy wrapper data to work with */
- dummychan.type = ANIMTYPE_SCENE;
- dummychan.data = sce;
- dummychan.id = &sce->id;
- dummychan.adt = sce->adt;
-
- ac.ads = ads;
- ac.data = &dummychan;
- ac.datatype = ANIMCONT_CHANNEL;
-
- /* get F-Curves to take keyframes from */
- filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* loop through each F-Curve, grabbing the keyframes */
- for (ale = anim_data.first; ale; ale = ale->next) {
- fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
- }
-
- ANIM_animdata_freelist(&anim_data);
-}
-
-void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, int saction_flag)
-{
- bAnimContext ac = {NULL};
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- bAnimListElem dummychan = {NULL};
- Base dummybase = {NULL};
-
- if (ob == NULL) {
- return;
- }
-
- /* create a dummy wrapper data to work with */
- dummybase.object = ob;
-
- dummychan.type = ANIMTYPE_OBJECT;
- dummychan.data = &dummybase;
- dummychan.id = &ob->id;
- dummychan.adt = ob->adt;
-
- ac.ads = ads;
- ac.data = &dummychan;
- ac.datatype = ANIMCONT_CHANNEL;
-
- /* get F-Curves to take keyframes from */
- filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* loop through each F-Curve, grabbing the keyframes */
- for (ale = anim_data.first; ale; ale = ale->next) {
- fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
- }
-
- ANIM_animdata_freelist(&anim_data);
-}
-
-void cachefile_to_keylist(bDopeSheet *ads,
- CacheFile *cache_file,
- DLRBT_Tree *keys,
- int saction_flag)
-{
- if (cache_file == NULL) {
- return;
- }
-
- /* create a dummy wrapper data to work with */
- bAnimListElem dummychan = {NULL};
- dummychan.type = ANIMTYPE_DSCACHEFILE;
- dummychan.data = cache_file;
- dummychan.id = &cache_file->id;
- dummychan.adt = cache_file->adt;
-
- bAnimContext ac = {NULL};
- ac.ads = ads;
- ac.data = &dummychan;
- ac.datatype = ANIMCONT_CHANNEL;
-
- /* get F-Curves to take keyframes from */
- ListBase anim_data = {NULL, NULL};
- int filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* loop through each F-Curve, grabbing the keyframes */
- LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
- fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
- }
-
- ANIM_animdata_freelist(&anim_data);
-}
-
-void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, int saction_flag)
-{
- if (fcu && fcu->totvert && fcu->bezt) {
- /* apply NLA-mapping (if applicable) */
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
- }
-
- /* Check if the curve is cyclic. */
- bool is_cyclic = BKE_fcurve_is_cyclic(fcu) && (fcu->totvert >= 2);
- bool do_extremes = (saction_flag & SACTION_SHOW_EXTREMES) != 0;
-
- /* loop through beztriples, making ActKeysColumns */
- BezTripleChain chain = {0};
-
- for (int v = 0; v < fcu->totvert; v++) {
- chain.cur = &fcu->bezt[v];
-
- /* Neighbor keys, accounting for being cyclic. */
- if (do_extremes) {
- chain.prev = (v > 0) ? &fcu->bezt[v - 1] : is_cyclic ? &fcu->bezt[fcu->totvert - 2] : NULL;
- chain.next = (v + 1 < fcu->totvert) ? &fcu->bezt[v + 1] : is_cyclic ? &fcu->bezt[1] : NULL;
- }
-
- add_bezt_to_keycolumns_list(keys, &chain);
- }
-
- /* Update keyblocks. */
- update_keyblocks(keys, fcu->bezt, fcu->totvert);
-
- /* unapply NLA-mapping if applicable */
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
- }
- }
-}
-
-void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, DLRBT_Tree *keys, int saction_flag)
-{
- FCurve *fcu;
-
- if (agrp) {
- /* loop through F-Curves */
- for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) {
- fcurve_to_keylist(adt, fcu, keys, saction_flag);
- }
- }
-}
-
-void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, int saction_flag)
-{
- FCurve *fcu;
-
- if (act) {
- /* loop through F-Curves */
- for (fcu = act->curves.first; fcu; fcu = fcu->next) {
- fcurve_to_keylist(adt, fcu, keys, saction_flag);
- }
- }
-}
-
-void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys, const bool active)
-{
- bGPDlayer *gpl;
-
- if (gpd && keys) {
- /* for now, just aggregate out all the frames, but only for visible layers */
- for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) {
- if ((gpl->flag & GP_LAYER_HIDE) == 0) {
- if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) {
- gpl_to_keylist(ads, gpl, keys);
- }
- }
- }
- }
-}
-
-void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys)
-{
- bGPDframe *gpf;
-
- if (gpl && keys) {
- /* Although the frames should already be in an ordered list,
- * they are not suitable for displaying yet. */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- add_gpframe_to_keycolumns_list(keys, gpf);
- }
-
- update_keyblocks(keys, NULL, 0);
- }
-}
-
-void mask_to_keylist(bDopeSheet *UNUSED(ads), MaskLayer *masklay, DLRBT_Tree *keys)
-{
- MaskLayerShape *masklay_shape;
-
- if (masklay && keys) {
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
- add_masklay_to_keycolumns_list(keys, masklay_shape);
- }
-
- update_keyblocks(keys, NULL, 0);
- }
-}
diff --git a/source/blender/editors/animation/keyframes_keylist.c b/source/blender/editors/animation/keyframes_keylist.c
new file mode 100644
index 00000000000..47ed2b56300
--- /dev/null
+++ b/source/blender/editors/animation/keyframes_keylist.c
@@ -0,0 +1,793 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edanimation
+ */
+
+/* System includes ----------------------------------------------------- */
+
+#include <float.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_dlrbTree.h"
+#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_cachefile_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mask_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_fcurve.h"
+
+#include "ED_anim_api.h"
+#include "ED_keyframes_keylist.h"
+
+/* *************************** Keyframe Processing *************************** */
+
+/* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
+
+BLI_INLINE bool is_cfra_eq(float a, float b)
+{
+ return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH);
+}
+
+BLI_INLINE bool is_cfra_lt(float a, float b)
+{
+ return (b - a) > BEZT_BINARYSEARCH_THRESH;
+}
+
+/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
+/* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */
+short compare_ak_cfraPtr(void *node, void *data)
+{
+ ActKeyColumn *ak = (ActKeyColumn *)node;
+ const float *cframe = data;
+ float val = *cframe;
+
+ if (is_cfra_eq(val, ak->cfra)) {
+ return 0;
+ }
+
+ if (val < ak->cfra) {
+ return -1;
+ }
+ return 1;
+}
+
+/* --------------- */
+
+/* Set of references to three logically adjacent keys. */
+typedef struct BezTripleChain {
+ /* Current keyframe. */
+ BezTriple *cur;
+
+ /* Logical neighbors. May be NULL. */
+ BezTriple *prev, *next;
+} BezTripleChain;
+
+/* Categorize the interpolation & handle type of the keyframe. */
+static eKeyframeHandleDrawOpts bezt_handle_type(BezTriple *bezt)
+{
+ if (bezt->h1 == HD_AUTO_ANIM && bezt->h2 == HD_AUTO_ANIM) {
+ return KEYFRAME_HANDLE_AUTO_CLAMP;
+ }
+ if (ELEM(bezt->h1, HD_AUTO_ANIM, HD_AUTO) && ELEM(bezt->h2, HD_AUTO_ANIM, HD_AUTO)) {
+ return KEYFRAME_HANDLE_AUTO;
+ }
+ if (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) {
+ return KEYFRAME_HANDLE_VECTOR;
+ }
+ if (ELEM(HD_FREE, bezt->h1, bezt->h2)) {
+ return KEYFRAME_HANDLE_FREE;
+ }
+ return KEYFRAME_HANDLE_ALIGNED;
+}
+
+/* Determine if the keyframe is an extreme by comparing with neighbors.
+ * Ends of fixed-value sections and of the whole curve are also marked.
+ */
+static eKeyframeExtremeDrawOpts bezt_extreme_type(BezTripleChain *chain)
+{
+ if (chain->prev == NULL && chain->next == NULL) {
+ return KEYFRAME_EXTREME_NONE;
+ }
+
+ /* Keyframe values for the current one and neighbors. */
+ float cur_y = chain->cur->vec[1][1];
+ float prev_y = cur_y, next_y = cur_y;
+
+ if (chain->prev && !IS_EQF(cur_y, chain->prev->vec[1][1])) {
+ prev_y = chain->prev->vec[1][1];
+ }
+ if (chain->next && !IS_EQF(cur_y, chain->next->vec[1][1])) {
+ next_y = chain->next->vec[1][1];
+ }
+
+ /* Static hold. */
+ if (prev_y == cur_y && next_y == cur_y) {
+ return KEYFRAME_EXTREME_FLAT;
+ }
+
+ /* Middle of an incline. */
+ if ((prev_y < cur_y && next_y > cur_y) || (prev_y > cur_y && next_y < cur_y)) {
+ return KEYFRAME_EXTREME_NONE;
+ }
+
+ /* Bezier handle values for the overshoot check. */
+ bool l_bezier = chain->prev && chain->prev->ipo == BEZT_IPO_BEZ;
+ bool r_bezier = chain->next && chain->cur->ipo == BEZT_IPO_BEZ;
+ float handle_l = l_bezier ? chain->cur->vec[0][1] : cur_y;
+ float handle_r = r_bezier ? chain->cur->vec[2][1] : cur_y;
+
+ /* Detect extremes. One of the neighbors is allowed to be equal to current. */
+ if (prev_y < cur_y || next_y < cur_y) {
+ bool is_overshoot = (handle_l > cur_y || handle_r > cur_y);
+
+ return KEYFRAME_EXTREME_MAX | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0);
+ }
+
+ if (prev_y > cur_y || next_y > cur_y) {
+ bool is_overshoot = (handle_l < cur_y || handle_r < cur_y);
+
+ return KEYFRAME_EXTREME_MIN | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0);
+ }
+
+ return KEYFRAME_EXTREME_NONE;
+}
+
+/* Comparator callback used for ActKeyColumns and BezTripleChain */
+static short compare_ak_bezt(void *node, void *data)
+{
+ BezTripleChain *chain = data;
+
+ return compare_ak_cfraPtr(node, &chain->cur->vec[1][0]);
+}
+
+/* New node callback used for building ActKeyColumns from BezTripleChain */
+static DLRBT_Node *nalloc_ak_bezt(void *data)
+{
+ ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
+ BezTripleChain *chain = data;
+ BezTriple *bezt = chain->cur;
+
+ /* store settings based on state of BezTriple */
+ ak->cfra = bezt->vec[1][0];
+ ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0;
+ ak->key_type = BEZKEYTYPE(bezt);
+ ak->handle_type = bezt_handle_type(bezt);
+ ak->extreme_type = bezt_extreme_type(chain);
+
+ /* count keyframes in this column */
+ ak->totkey = 1;
+
+ return (DLRBT_Node *)ak;
+}
+
+/* Node updater callback used for building ActKeyColumns from BezTripleChain */
+static void nupdate_ak_bezt(void *node, void *data)
+{
+ ActKeyColumn *ak = node;
+ BezTripleChain *chain = data;
+ BezTriple *bezt = chain->cur;
+
+ /* set selection status and 'touched' status */
+ if (BEZT_ISSEL_ANY(bezt)) {
+ ak->sel = SELECT;
+ }
+
+ /* count keyframes in this column */
+ ak->totkey++;
+
+ /* For keyframe type, 'proper' keyframes have priority over breakdowns
+ * (and other types for now). */
+ if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME) {
+ ak->key_type = BEZT_KEYTYPE_KEYFRAME;
+ }
+
+ /* For interpolation type, select the highest value (enum is sorted). */
+ ak->handle_type = MAX2(ak->handle_type, bezt_handle_type(bezt));
+
+ /* For extremes, detect when combining different states. */
+ char new_extreme = bezt_extreme_type(chain);
+
+ if (new_extreme != ak->extreme_type) {
+ /* Replace the flat status without adding mixed. */
+ if (ak->extreme_type == KEYFRAME_EXTREME_FLAT) {
+ ak->extreme_type = new_extreme;
+ }
+ else if (new_extreme != KEYFRAME_EXTREME_FLAT) {
+ ak->extreme_type |= (new_extreme | KEYFRAME_EXTREME_MIXED);
+ }
+ }
+}
+
+/* ......... */
+
+/* Comparator callback used for ActKeyColumns and GPencil frame */
+static short compare_ak_gpframe(void *node, void *data)
+{
+ bGPDframe *gpf = (bGPDframe *)data;
+
+ float frame = gpf->framenum;
+ return compare_ak_cfraPtr(node, &frame);
+}
+
+/* New node callback used for building ActKeyColumns from GPencil frames */
+static DLRBT_Node *nalloc_ak_gpframe(void *data)
+{
+ ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF");
+ bGPDframe *gpf = (bGPDframe *)data;
+
+ /* store settings based on state of BezTriple */
+ ak->cfra = gpf->framenum;
+ ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0;
+ ak->key_type = gpf->key_type;
+
+ /* count keyframes in this column */
+ ak->totkey = 1;
+ /* Set as visible block. */
+ ak->totblock = 1;
+ ak->block.sel = ak->sel;
+ ak->block.flag |= ACTKEYBLOCK_FLAG_GPENCIL;
+
+ return (DLRBT_Node *)ak;
+}
+
+/* Node updater callback used for building ActKeyColumns from GPencil frames */
+static void nupdate_ak_gpframe(void *node, void *data)
+{
+ ActKeyColumn *ak = (ActKeyColumn *)node;
+ bGPDframe *gpf = (bGPDframe *)data;
+
+ /* set selection status and 'touched' status */
+ if (gpf->flag & GP_FRAME_SELECT) {
+ ak->sel = SELECT;
+ }
+
+ /* count keyframes in this column */
+ ak->totkey++;
+
+ /* for keyframe type, 'proper' keyframes have priority over breakdowns
+ * (and other types for now). */
+ if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME) {
+ ak->key_type = BEZT_KEYTYPE_KEYFRAME;
+ }
+}
+
+/* ......... */
+
+/* Comparator callback used for ActKeyColumns and GPencil frame */
+static short compare_ak_masklayshape(void *node, void *data)
+{
+ MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
+
+ float frame = masklay_shape->frame;
+ return compare_ak_cfraPtr(node, &frame);
+}
+
+/* New node callback used for building ActKeyColumns from GPencil frames */
+static DLRBT_Node *nalloc_ak_masklayshape(void *data)
+{
+ ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF");
+ MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
+
+ /* store settings based on state of BezTriple */
+ ak->cfra = masklay_shape->frame;
+ ak->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? SELECT : 0;
+
+ /* count keyframes in this column */
+ ak->totkey = 1;
+
+ return (DLRBT_Node *)ak;
+}
+
+/* Node updater callback used for building ActKeyColumns from GPencil frames */
+static void nupdate_ak_masklayshape(void *node, void *data)
+{
+ ActKeyColumn *ak = (ActKeyColumn *)node;
+ MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
+
+ /* set selection status and 'touched' status */
+ if (masklay_shape->flag & MASK_SHAPE_SELECT) {
+ ak->sel = SELECT;
+ }
+
+ /* count keyframes in this column */
+ ak->totkey++;
+}
+
+/* --------------- */
+
+/* Add the given BezTriple to the given 'list' of Keyframes */
+static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTripleChain *bezt)
+{
+ if (ELEM(NULL, keys, bezt)) {
+ return;
+ }
+
+ BLI_dlrbTree_add(keys, compare_ak_bezt, nalloc_ak_bezt, nupdate_ak_bezt, bezt);
+}
+
+/* Add the given GPencil Frame to the given 'list' of Keyframes */
+static void add_gpframe_to_keycolumns_list(DLRBT_Tree *keys, bGPDframe *gpf)
+{
+ if (ELEM(NULL, keys, gpf)) {
+ return;
+ }
+
+ BLI_dlrbTree_add(keys, compare_ak_gpframe, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf);
+}
+
+/* Add the given MaskLayerShape Frame to the given 'list' of Keyframes */
+static void add_masklay_to_keycolumns_list(DLRBT_Tree *keys, MaskLayerShape *masklay_shape)
+{
+ if (ELEM(NULL, keys, masklay_shape)) {
+ return;
+ }
+
+ BLI_dlrbTree_add(keys,
+ compare_ak_masklayshape,
+ nalloc_ak_masklayshape,
+ nupdate_ak_masklayshape,
+ masklay_shape);
+}
+
+/* ActKeyBlocks (Long Keyframes) ------------------------------------------ */
+
+static const ActKeyBlockInfo dummy_keyblock = {0};
+
+static void compute_keyblock_data(ActKeyBlockInfo *info, BezTriple *prev, BezTriple *beztn)
+{
+ memset(info, 0, sizeof(ActKeyBlockInfo));
+
+ if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) {
+ /* Animator tagged a "moving hold"
+ * - Previous key must also be tagged as a moving hold, otherwise
+ * we're just dealing with the first of a pair, and we don't
+ * want to be creating any phantom holds...
+ */
+ if (BEZKEYTYPE(prev) == BEZT_KEYTYPE_MOVEHOLD) {
+ info->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
+ }
+ }
+
+ /* Check for same values...
+ * - Handles must have same central value as each other
+ * - Handles which control that section of the curve must be constant
+ */
+ if (IS_EQF(beztn->vec[1][1], prev->vec[1][1])) {
+ bool hold;
+
+ /* Only check handles in case of actual bezier interpolation. */
+ if (prev->ipo == BEZT_IPO_BEZ) {
+ hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) &&
+ IS_EQF(prev->vec[1][1], prev->vec[2][1]);
+ }
+ /* This interpolation type induces movement even between identical keys. */
+ else {
+ hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC);
+ }
+
+ if (hold) {
+ info->flag |= ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
+ }
+ }
+
+ /* Remember non-bezier interpolation info. */
+ if (prev->ipo != BEZT_IPO_BEZ) {
+ info->flag |= ACTKEYBLOCK_FLAG_NON_BEZIER;
+ }
+
+ info->sel = BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn);
+}
+
+static void add_keyblock_info(ActKeyColumn *col, const ActKeyBlockInfo *block)
+{
+ /* New curve and block. */
+ if (col->totcurve <= 1 && col->totblock == 0) {
+ memcpy(&col->block, block, sizeof(ActKeyBlockInfo));
+ }
+ /* Existing curve. */
+ else {
+ col->block.conflict |= (col->block.flag ^ block->flag);
+ col->block.flag |= block->flag;
+ col->block.sel |= block->sel;
+ }
+
+ if (block->flag) {
+ col->totblock++;
+ }
+}
+
+static void add_bezt_to_keyblocks_list(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
+{
+ ActKeyColumn *col = keys->first;
+
+ if (bezt && bezt_len >= 2) {
+ ActKeyBlockInfo block;
+
+ /* Find the first key column while inserting dummy blocks. */
+ for (; col != NULL && is_cfra_lt(col->cfra, bezt[0].vec[1][0]); col = col->next) {
+ add_keyblock_info(col, &dummy_keyblock);
+ }
+
+ BLI_assert(col != NULL);
+
+ /* Insert real blocks. */
+ for (int v = 1; col != NULL && v < bezt_len; v++, bezt++) {
+ /* Wrong order of bezier keys: resync position. */
+ if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) {
+ /* Backtrack to find the right location. */
+ if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) {
+ ActKeyColumn *newcol = (ActKeyColumn *)BLI_dlrbTree_search_exact(
+ keys, compare_ak_cfraPtr, &bezt[1].vec[1][0]);
+
+ if (newcol != NULL) {
+ col = newcol;
+
+ /* The previous keyblock is garbage too. */
+ if (col->prev != NULL) {
+ add_keyblock_info(col->prev, &dummy_keyblock);
+ }
+ }
+ else {
+ BLI_assert(false);
+ }
+ }
+
+ continue;
+ }
+
+ /* Normal sequence */
+ BLI_assert(is_cfra_eq(col->cfra, bezt[0].vec[1][0]));
+
+ compute_keyblock_data(&block, bezt, bezt + 1);
+
+ for (; col != NULL && is_cfra_lt(col->cfra, bezt[1].vec[1][0]); col = col->next) {
+ add_keyblock_info(col, &block);
+ }
+
+ BLI_assert(col != NULL);
+ }
+ }
+
+ /* Insert dummy blocks at the end. */
+ for (; col != NULL; col = col->next) {
+ add_keyblock_info(col, &dummy_keyblock);
+ }
+}
+
+/* Walk through columns and propagate blocks and totcurve.
+ *
+ * This must be called even by animation sources that don't generate
+ * keyblocks to keep the data structure consistent after adding columns.
+ */
+static void update_keyblocks(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
+{
+ /* Recompute the prev/next linked list. */
+ BLI_dlrbTree_linkedlist_sync(keys);
+
+ /* Find the curve count */
+ int max_curve = 0;
+
+ LISTBASE_FOREACH (ActKeyColumn *, col, keys) {
+ max_curve = MAX2(max_curve, col->totcurve);
+ }
+
+ /* Propagate blocks to inserted keys */
+ ActKeyColumn *prev_ready = NULL;
+
+ LISTBASE_FOREACH (ActKeyColumn *, col, keys) {
+ /* Pre-existing column. */
+ if (col->totcurve > 0) {
+ prev_ready = col;
+ }
+ /* Newly inserted column, so copy block data from previous. */
+ else if (prev_ready != NULL) {
+ col->totblock = prev_ready->totblock;
+ memcpy(&col->block, &prev_ready->block, sizeof(ActKeyBlockInfo));
+ }
+
+ col->totcurve = max_curve + 1;
+ }
+
+ /* Add blocks on top */
+ add_bezt_to_keyblocks_list(keys, bezt, bezt_len);
+}
+
+/* --------- */
+
+bool actkeyblock_is_valid(ActKeyColumn *ac)
+{
+ return ac != NULL && ac->next != NULL && ac->totblock > 0;
+}
+
+/* Checks if ActKeyBlock should exist... */
+int actkeyblock_get_valid_hold(ActKeyColumn *ac)
+{
+ /* check that block is valid */
+ if (!actkeyblock_is_valid(ac)) {
+ return 0;
+ }
+
+ const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD);
+ return (ac->block.flag & ~ac->block.conflict) & hold_mask;
+}
+
+/* *************************** Keyframe List Conversions *************************** */
+
+void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, int saction_flag)
+{
+ if (ac) {
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ /* get F-Curves to take keyframes from */
+ filter = ANIMFILTER_DATA_VISIBLE;
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* loop through each F-Curve, grabbing the keyframes */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ /* Why not use all #eAnim_KeyType here?
+ * All of the other key types are actually "summaries" themselves,
+ * and will just end up duplicating stuff that comes up through
+ * standard filtering of just F-Curves. Given the way that these work,
+ * there isn't really any benefit at all from including them. - Aligorith */
+
+ switch (ale->datatype) {
+ case ALE_FCURVE:
+ fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
+ break;
+ case ALE_MASKLAY:
+ mask_to_keylist(ac->ads, ale->data, keys);
+ break;
+ case ALE_GPFRAME:
+ gpl_to_keylist(ac->ads, ale->data, keys);
+ break;
+ default:
+ // printf("%s: datatype %d unhandled\n", __func__, ale->datatype);
+ break;
+ }
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+ }
+}
+
+void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, int saction_flag)
+{
+ bAnimContext ac = {NULL};
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ bAnimListElem dummychan = {NULL};
+
+ if (sce == NULL) {
+ return;
+ }
+
+ /* create a dummy wrapper data to work with */
+ dummychan.type = ANIMTYPE_SCENE;
+ dummychan.data = sce;
+ dummychan.id = &sce->id;
+ dummychan.adt = sce->adt;
+
+ ac.ads = ads;
+ ac.data = &dummychan;
+ ac.datatype = ANIMCONT_CHANNEL;
+
+ /* get F-Curves to take keyframes from */
+ filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* loop through each F-Curve, grabbing the keyframes */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+}
+
+void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, int saction_flag)
+{
+ bAnimContext ac = {NULL};
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ bAnimListElem dummychan = {NULL};
+ Base dummybase = {NULL};
+
+ if (ob == NULL) {
+ return;
+ }
+
+ /* create a dummy wrapper data to work with */
+ dummybase.object = ob;
+
+ dummychan.type = ANIMTYPE_OBJECT;
+ dummychan.data = &dummybase;
+ dummychan.id = &ob->id;
+ dummychan.adt = ob->adt;
+
+ ac.ads = ads;
+ ac.data = &dummychan;
+ ac.datatype = ANIMCONT_CHANNEL;
+
+ /* get F-Curves to take keyframes from */
+ filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* loop through each F-Curve, grabbing the keyframes */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+}
+
+void cachefile_to_keylist(bDopeSheet *ads,
+ CacheFile *cache_file,
+ DLRBT_Tree *keys,
+ int saction_flag)
+{
+ if (cache_file == NULL) {
+ return;
+ }
+
+ /* create a dummy wrapper data to work with */
+ bAnimListElem dummychan = {NULL};
+ dummychan.type = ANIMTYPE_DSCACHEFILE;
+ dummychan.data = cache_file;
+ dummychan.id = &cache_file->id;
+ dummychan.adt = cache_file->adt;
+
+ bAnimContext ac = {NULL};
+ ac.ads = ads;
+ ac.data = &dummychan;
+ ac.datatype = ANIMCONT_CHANNEL;
+
+ /* get F-Curves to take keyframes from */
+ ListBase anim_data = {NULL, NULL};
+ int filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* loop through each F-Curve, grabbing the keyframes */
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
+ fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+}
+
+void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, int saction_flag)
+{
+ if (fcu && fcu->totvert && fcu->bezt) {
+ /* apply NLA-mapping (if applicable) */
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
+ }
+
+ /* Check if the curve is cyclic. */
+ bool is_cyclic = BKE_fcurve_is_cyclic(fcu) && (fcu->totvert >= 2);
+ bool do_extremes = (saction_flag & SACTION_SHOW_EXTREMES) != 0;
+
+ /* loop through beztriples, making ActKeysColumns */
+ BezTripleChain chain = {0};
+
+ for (int v = 0; v < fcu->totvert; v++) {
+ chain.cur = &fcu->bezt[v];
+
+ /* Neighbor keys, accounting for being cyclic. */
+ if (do_extremes) {
+ chain.prev = (v > 0) ? &fcu->bezt[v - 1] : is_cyclic ? &fcu->bezt[fcu->totvert - 2] : NULL;
+ chain.next = (v + 1 < fcu->totvert) ? &fcu->bezt[v + 1] : is_cyclic ? &fcu->bezt[1] : NULL;
+ }
+
+ add_bezt_to_keycolumns_list(keys, &chain);
+ }
+
+ /* Update keyblocks. */
+ update_keyblocks(keys, fcu->bezt, fcu->totvert);
+
+ /* unapply NLA-mapping if applicable */
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
+ }
+ }
+}
+
+void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, DLRBT_Tree *keys, int saction_flag)
+{
+ FCurve *fcu;
+
+ if (agrp) {
+ /* loop through F-Curves */
+ for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) {
+ fcurve_to_keylist(adt, fcu, keys, saction_flag);
+ }
+ }
+}
+
+void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, int saction_flag)
+{
+ FCurve *fcu;
+
+ if (act) {
+ /* loop through F-Curves */
+ for (fcu = act->curves.first; fcu; fcu = fcu->next) {
+ fcurve_to_keylist(adt, fcu, keys, saction_flag);
+ }
+ }
+}
+
+void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys, const bool active)
+{
+ bGPDlayer *gpl;
+
+ if (gpd && keys) {
+ /* for now, just aggregate out all the frames, but only for visible layers */
+ for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) {
+ if ((gpl->flag & GP_LAYER_HIDE) == 0) {
+ if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) {
+ gpl_to_keylist(ads, gpl, keys);
+ }
+ }
+ }
+ }
+}
+
+void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys)
+{
+ bGPDframe *gpf;
+
+ if (gpl && keys) {
+ /* Although the frames should already be in an ordered list,
+ * they are not suitable for displaying yet. */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ add_gpframe_to_keycolumns_list(keys, gpf);
+ }
+
+ update_keyblocks(keys, NULL, 0);
+ }
+}
+
+void mask_to_keylist(bDopeSheet *UNUSED(ads), MaskLayer *masklay, DLRBT_Tree *keys)
+{
+ MaskLayerShape *masklay_shape;
+
+ if (masklay && keys) {
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape->next) {
+ add_masklay_to_keycolumns_list(keys, masklay_shape);
+ }
+
+ update_keyblocks(keys, NULL, 0);
+ }
+}
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index df3550d5db6..b727e1c176d 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -62,7 +62,7 @@
#include "ED_anim_api.h"
#include "ED_armature.h"
-#include "ED_keyframes_draw.h"
+#include "ED_keyframes_keylist.h"
#include "ED_keyframes_edit.h"
#include "ED_keyframing.h"
#include "ED_object.h"
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 1a1685e4a01..675af6eada9 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -77,7 +77,7 @@
#include "UI_resources.h"
#include "ED_armature.h"
-#include "ED_keyframes_draw.h"
+#include "ED_keyframes_keylist.h"
#include "ED_markers.h"
#include "ED_numinput.h"
#include "ED_screen.h"
diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h
index 2f8faf1b2bd..ac6dd7dce32 100644
--- a/source/blender/editors/include/ED_keyframes_draw.h
+++ b/source/blender/editors/include/ED_keyframes_draw.h
@@ -42,99 +42,6 @@ struct bAnimContext;
struct bDopeSheet;
struct bGPDlayer;
-/* ****************************** Base Structs ****************************** */
-
-/* Information about the stretch of time from current to the next column */
-typedef struct ActKeyBlockInfo {
- /* Combination of flags from all curves. */
- short flag;
- /* Mask of flags that differ between curves. */
- short conflict;
-
- /* Selection flag. */
- char sel;
-} ActKeyBlockInfo;
-
-/* Keyframe Column Struct */
-typedef struct ActKeyColumn {
- /* ListBase linkage */
- struct ActKeyColumn *next, *prev;
-
- /* sorting-tree linkage */
- /** 'children' of this node, less than and greater than it (respectively) */
- struct ActKeyColumn *left, *right;
- /** parent of this node in the tree */
- struct ActKeyColumn *parent;
- /** DLRB_BLACK or DLRB_RED */
- char tree_col;
-
- /* keyframe info */
- /** eBezTripe_KeyframeType */
- char key_type;
- /** eKeyframeHandleDrawOpts */
- char handle_type;
- /** eKeyframeExtremeDrawOpts */
- char extreme_type;
- short sel;
- float cfra;
-
- /* key-block info */
- ActKeyBlockInfo block;
-
- /* number of curves and keys in this column */
- short totcurve, totkey, totblock;
-} ActKeyColumn;
-
-/* ActKeyBlockInfo - Flag */
-typedef enum eActKeyBlock_Hold {
- /* Key block represents a moving hold */
- ACTKEYBLOCK_FLAG_MOVING_HOLD = (1 << 0),
- /* Key block represents a static hold */
- ACTKEYBLOCK_FLAG_STATIC_HOLD = (1 << 1),
- /* Key block represents any kind of hold */
- ACTKEYBLOCK_FLAG_ANY_HOLD = (1 << 2),
- /* The curve segment uses non-bezier interpolation */
- ACTKEYBLOCK_FLAG_NON_BEZIER = (1 << 3),
- /* The block is grease pencil */
- ACTKEYBLOCK_FLAG_GPENCIL = (1 << 4),
-} eActKeyBlock_Flag;
-
-/* *********************** Keyframe Drawing ****************************** */
-
-/* options for keyframe shape drawing */
-typedef enum eKeyframeShapeDrawOpts {
- /* only the border */
- KEYFRAME_SHAPE_FRAME = 0,
- /* only the inside filling */
- KEYFRAME_SHAPE_INSIDE,
- /* the whole thing */
- KEYFRAME_SHAPE_BOTH,
-} eKeyframeShapeDrawOpts;
-
-/* Handle type. */
-typedef enum eKeyframeHandleDrawOpts {
- /* Don't draw */
- KEYFRAME_HANDLE_NONE = 0,
- /* Various marks in order of increasing display priority. */
- KEYFRAME_HANDLE_AUTO_CLAMP,
- KEYFRAME_HANDLE_AUTO,
- KEYFRAME_HANDLE_VECTOR,
- KEYFRAME_HANDLE_ALIGNED,
- KEYFRAME_HANDLE_FREE,
-} eKeyframeHandleDrawOpts;
-
-/* Extreme type. */
-typedef enum eKeyframeExtremeDrawOpts {
- KEYFRAME_EXTREME_NONE = 0,
- /* Minimum/maximum present. */
- KEYFRAME_EXTREME_MIN = (1 << 0),
- KEYFRAME_EXTREME_MAX = (1 << 1),
- /* Grouped keys have different states. */
- KEYFRAME_EXTREME_MIXED = (1 << 2),
- /* Both neighbors are equal to this key. */
- KEYFRAME_EXTREME_FLAT = (1 << 3),
-} eKeyframeExtremeDrawOpts;
-
/* draw simple diamond-shape keyframe */
/* caller should set up vertex format, bind GPU_SHADER_KEYFRAME_DIAMOND,
* immBegin(GPU_PRIM_POINTS, n), then call this n times */
@@ -216,59 +123,6 @@ void draw_masklay_channel(struct View2D *v2d,
float yscale_fac,
int saction_flag);
-/* Keydata Generation --------------- */
-/* F-Curve */
-void fcurve_to_keylist(struct AnimData *adt,
- struct FCurve *fcu,
- struct DLRBT_Tree *keys,
- int saction_flag);
-/* Action Group */
-void agroup_to_keylist(struct AnimData *adt,
- struct bActionGroup *agrp,
- struct DLRBT_Tree *keys,
- int saction_flag);
-/* Action */
-void action_to_keylist(struct AnimData *adt,
- struct bAction *act,
- struct DLRBT_Tree *keys,
- int saction_flag);
-/* Object */
-void ob_to_keylist(struct bDopeSheet *ads,
- struct Object *ob,
- struct DLRBT_Tree *keys,
- int saction_flag);
-/* Cache File */
-void cachefile_to_keylist(struct bDopeSheet *ads,
- struct CacheFile *cache_file,
- struct DLRBT_Tree *keys,
- int saction_flag);
-/* Scene */
-void scene_to_keylist(struct bDopeSheet *ads,
- struct Scene *sce,
- struct DLRBT_Tree *keys,
- int saction_flag);
-/* DopeSheet Summary */
-void summary_to_keylist(struct bAnimContext *ac, struct DLRBT_Tree *keys, int saction_flag);
-/* Grease Pencil datablock summary */
-void gpencil_to_keylist(struct bDopeSheet *ads,
- struct bGPdata *gpd,
- struct DLRBT_Tree *keys,
- const bool active);
-/* Grease Pencil Layer */
-void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys);
-/* Mask */
-void mask_to_keylist(struct bDopeSheet *ads, struct MaskLayer *masklay, struct DLRBT_Tree *keys);
-
-/* ActKeyColumn API ---------------- */
-/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
-short compare_ak_cfraPtr(void *node, void *data);
-
-/* Checks if ActKeyColumn has any block data */
-bool actkeyblock_is_valid(ActKeyColumn *ac);
-
-/* Checks if ActKeyColumn can be used as a block (i.e. drawn/used to detect "holds") */
-int actkeyblock_get_valid_hold(ActKeyColumn *ac);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_keyframes_keylist.h b/source/blender/editors/include/ED_keyframes_keylist.h
new file mode 100644
index 00000000000..3d5b70183df
--- /dev/null
+++ b/source/blender/editors/include/ED_keyframes_keylist.h
@@ -0,0 +1,195 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) (C) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AnimData;
+struct CacheFile;
+struct DLRBT_Tree;
+struct FCurve;
+struct ListBase;
+struct MaskLayer;
+struct Object;
+struct Scene;
+struct View2D;
+struct bAction;
+struct bActionGroup;
+struct bAnimContext;
+struct bDopeSheet;
+struct bGPDlayer;
+
+/* ****************************** Base Structs ****************************** */
+
+/* Information about the stretch of time from current to the next column */
+typedef struct ActKeyBlockInfo {
+ /* Combination of flags from all curves. */
+ short flag;
+ /* Mask of flags that differ between curves. */
+ short conflict;
+
+ /* Selection flag. */
+ char sel;
+} ActKeyBlockInfo;
+
+/* Keyframe Column Struct */
+typedef struct ActKeyColumn {
+ /* ListBase linkage */
+ struct ActKeyColumn *next, *prev;
+
+ /* sorting-tree linkage */
+ /** 'children' of this node, less than and greater than it (respectively) */
+ struct ActKeyColumn *left, *right;
+ /** parent of this node in the tree */
+ struct ActKeyColumn *parent;
+ /** DLRB_BLACK or DLRB_RED */
+ char tree_col;
+
+ /* keyframe info */
+ /** eBezTripe_KeyframeType */
+ char key_type;
+ /** eKeyframeHandleDrawOpts */
+ char handle_type;
+ /** eKeyframeExtremeDrawOpts */
+ char extreme_type;
+ short sel;
+ float cfra;
+
+ /* key-block info */
+ ActKeyBlockInfo block;
+
+ /* number of curves and keys in this column */
+ short totcurve, totkey, totblock;
+} ActKeyColumn;
+
+/* ActKeyBlockInfo - Flag */
+typedef enum eActKeyBlock_Hold {
+ /* Key block represents a moving hold */
+ ACTKEYBLOCK_FLAG_MOVING_HOLD = (1 << 0),
+ /* Key block represents a static hold */
+ ACTKEYBLOCK_FLAG_STATIC_HOLD = (1 << 1),
+ /* Key block represents any kind of hold */
+ ACTKEYBLOCK_FLAG_ANY_HOLD = (1 << 2),
+ /* The curve segment uses non-bezier interpolation */
+ ACTKEYBLOCK_FLAG_NON_BEZIER = (1 << 3),
+ /* The block is grease pencil */
+ ACTKEYBLOCK_FLAG_GPENCIL = (1 << 4),
+} eActKeyBlock_Flag;
+
+/* *********************** Keyframe Drawing ****************************** */
+
+/* options for keyframe shape drawing */
+typedef enum eKeyframeShapeDrawOpts {
+ /* only the border */
+ KEYFRAME_SHAPE_FRAME = 0,
+ /* only the inside filling */
+ KEYFRAME_SHAPE_INSIDE,
+ /* the whole thing */
+ KEYFRAME_SHAPE_BOTH,
+} eKeyframeShapeDrawOpts;
+
+/* Handle type. */
+typedef enum eKeyframeHandleDrawOpts {
+ /* Don't draw */
+ KEYFRAME_HANDLE_NONE = 0,
+ /* Various marks in order of increasing display priority. */
+ KEYFRAME_HANDLE_AUTO_CLAMP,
+ KEYFRAME_HANDLE_AUTO,
+ KEYFRAME_HANDLE_VECTOR,
+ KEYFRAME_HANDLE_ALIGNED,
+ KEYFRAME_HANDLE_FREE,
+} eKeyframeHandleDrawOpts;
+
+/* Extreme type. */
+typedef enum eKeyframeExtremeDrawOpts {
+ KEYFRAME_EXTREME_NONE = 0,
+ /* Minimum/maximum present. */
+ KEYFRAME_EXTREME_MIN = (1 << 0),
+ KEYFRAME_EXTREME_MAX = (1 << 1),
+ /* Grouped keys have different states. */
+ KEYFRAME_EXTREME_MIXED = (1 << 2),
+ /* Both neighbors are equal to this key. */
+ KEYFRAME_EXTREME_FLAT = (1 << 3),
+} eKeyframeExtremeDrawOpts;
+
+/* ******************************* Methods ****************************** */
+
+/* Keydata Generation --------------- */
+/* F-Curve */
+void fcurve_to_keylist(struct AnimData *adt,
+ struct FCurve *fcu,
+ struct DLRBT_Tree *keys,
+ int saction_flag);
+/* Action Group */
+void agroup_to_keylist(struct AnimData *adt,
+ struct bActionGroup *agrp,
+ struct DLRBT_Tree *keys,
+ int saction_flag);
+/* Action */
+void action_to_keylist(struct AnimData *adt,
+ struct bAction *act,
+ struct DLRBT_Tree *keys,
+ int saction_flag);
+/* Object */
+void ob_to_keylist(struct bDopeSheet *ads,
+ struct Object *ob,
+ struct DLRBT_Tree *keys,
+ int saction_flag);
+/* Cache File */
+void cachefile_to_keylist(struct bDopeSheet *ads,
+ struct CacheFile *cache_file,
+ struct DLRBT_Tree *keys,
+ int saction_flag);
+/* Scene */
+void scene_to_keylist(struct bDopeSheet *ads,
+ struct Scene *sce,
+ struct DLRBT_Tree *keys,
+ int saction_flag);
+/* DopeSheet Summary */
+void summary_to_keylist(struct bAnimContext *ac, struct DLRBT_Tree *keys, int saction_flag);
+/* Grease Pencil datablock summary */
+void gpencil_to_keylist(struct bDopeSheet *ads,
+ struct bGPdata *gpd,
+ struct DLRBT_Tree *keys,
+ const bool active);
+/* Grease Pencil Layer */
+void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys);
+/* Mask */
+void mask_to_keylist(struct bDopeSheet *ads, struct MaskLayer *masklay, struct DLRBT_Tree *keys);
+
+/* ActKeyColumn API ---------------- */
+/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
+short compare_ak_cfraPtr(void *node, void *data);
+
+/* Checks if ActKeyColumn has any block data */
+bool actkeyblock_is_valid(ActKeyColumn *ac);
+
+/* Checks if ActKeyColumn can be used as a block (i.e. drawn/used to detect "holds") */
+int actkeyblock_get_valid_hold(ActKeyColumn *ac);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 43ac646f053..975c86f3e71 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -66,6 +66,7 @@
#include "ED_datafiles.h"
#include "ED_keyframes_draw.h"
+#include "ED_keyframes_keylist.h"
#include "ED_render.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index ffeaf514642..3d0d856b1c5 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -71,7 +71,7 @@
#include "ED_armature.h"
#include "ED_clip.h"
#include "ED_image.h"
-#include "ED_keyframes_draw.h"
+#include "ED_keyframes_keylist.h"
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_screen.h"
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 0d5b197ae93..677053ff577 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -51,7 +51,7 @@
#include "ED_anim_api.h"
#include "ED_gpencil.h"
-#include "ED_keyframes_draw.h"
+#include "ED_keyframes_keylist.h"
#include "ED_keyframes_edit.h"
#include "ED_markers.h"
#include "ED_mask.h"
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index f9fb386095d..c96047da0c8 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -44,6 +44,7 @@
#include "ED_anim_api.h"
#include "ED_keyframes_draw.h"
+#include "ED_keyframes_keylist.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"