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.
This commit is contained in:
parent
ceb612a79c
commit
132522cba8
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue