Dopesheet: Added "Moving Hold" as a keyframe type

Currently "long keyframes" are only useful for indicating where stationary
holds occur. If however you try to create a "moving hold" (where the values
are slightly different, but in terms of overall effect, it's still a hold)
then it could get tricky to keep track of where these occur.

Now it's possible to tag such keyframes (using the keyframe types - RKEY)
as being part of a moving hold. These will not only be drawn differently
from normal keyframes, but they will also result in a "long keyframe"
being drawn between each pair of them, just like if they had been completely
stationary instead.

Currently the theming/styling of these is a bit rough. They reuse the existing
theme colours for long keyframes.
This commit is contained in:
Joshua Leung 2016-07-07 23:37:15 +12:00
parent 2ba2860e11
commit f3b3eb70a6
9 changed files with 141 additions and 19 deletions

View File

@ -40,6 +40,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_dlrbTree.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@ -282,6 +283,9 @@ static ActKeyBlock *bezts_to_new_actkeyblock(BezTriple *prev, BezTriple *beztn)
ab->sel = (BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn)) ? SELECT : 0;
ab->modified = 1;
if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD)
ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD;
return ab;
}
@ -305,16 +309,28 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt
}
/* check if block needed - same value(s)?
* -> firstly, handles must have same central value as each other
* -> secondly, handles which control that section of the curve must be constant
*/
/* check if block needed */
if (prev == NULL) return;
if (IS_EQF(beztn->vec[1][1], prev->vec[1][1]) == 0) return;
if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) == 0) return;
if (IS_EQF(prev->vec[1][1], prev->vec[2][1]) == 0) return;
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)
return;
}
else {
/* 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]) == 0) return;
if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) == 0) return;
if (IS_EQF(prev->vec[1][1], prev->vec[2][1]) == 0) return;
}
/* if there are no blocks already, just add as root */
if (blocks->root == NULL) {
@ -340,7 +356,13 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt
*/
if (IS_EQT(ab->start, prev->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
/* set selection status and 'touched' status */
if (BEZT_ISSEL_ANY(beztn)) ab->sel = SELECT;
if (BEZT_ISSEL_ANY(beztn))
ab->sel = SELECT;
/* XXX: only when the first one was a moving hold? */
if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD)
ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD;
ab->modified++;
/* done... no need to insert */
@ -485,7 +507,27 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
/* tweak size of keyframe shape according to type of keyframe
* - 'proper' keyframes have key_type = 0, so get drawn at full size
*/
hsize -= 0.5f * key_type;
switch (key_type) {
case BEZT_KEYTYPE_KEYFRAME: /* must be full size */
break;
case BEZT_KEYTYPE_BREAKDOWN: /* slightly smaller than normal keyframe */
hsize *= 0.85f;
break;
case BEZT_KEYTYPE_MOVEHOLD: /* slightly smaller than normal keyframes (but by less than for breakdowns) */
//hsize *= 0.72f;
hsize *= 0.95f;
break;
case BEZT_KEYTYPE_EXTREME: /* slightly larger */
hsize *= 1.2f;
break;
default:
hsize -= 0.5f * key_type;
break;
}
/* adjust view transform before starting */
glTranslatef(x, y, 0.0f);
@ -518,6 +560,15 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
else UI_GetThemeColor4fv(TH_KEYTYPE_JITTER, inner_col);
break;
}
case BEZT_KEYTYPE_MOVEHOLD: /* similar to traditional keyframes, but different... */
{
/* XXX: Should these get their own theme options instead? */
if (sel) UI_GetThemeColorShade4fv(TH_STRIP_SELECT, 35, inner_col);
else UI_GetThemeColorShade4fv(TH_STRIP, 50, inner_col);
inner_col[3] = 1.0f; /* full opacity, to avoid problems with visual glitches */
break;
}
case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames (default theme) */
default:
{
@ -563,7 +614,10 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa
ActKeyBlock *ab;
float alpha;
float xscale;
float iconsize = (U.widget_unit / 4.0f) * yscale_fac;
const float iconsize = (U.widget_unit / 4.0f) * yscale_fac;
const float mhsize = iconsize * 0.7f;
glEnable(GL_BLEND);
/* get View2D scaling factor */
@ -576,6 +630,7 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa
/* draw keyblocks */
if (blocks) {
float sel_color[4], unsel_color[4];
float sel_mhcol[4], unsel_mhcol[4];
/* cache colours first */
UI_GetThemeColor4fv(TH_STRIP_SELECT, sel_color);
@ -584,16 +639,32 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa
sel_color[3] *= alpha;
unsel_color[3] *= alpha;
copy_v4_v4(sel_mhcol, sel_color);
sel_mhcol[3] *= 0.8f;
copy_v4_v4(unsel_mhcol, unsel_color);
unsel_mhcol[3] *= 0.8f;
/* NOTE: the tradeoff for changing colors between each draw is dwarfed by the cost of checking validity */
for (ab = blocks->first; ab; ab = ab->next) {
if (actkeyblock_is_valid(ab, keys)) {
/* draw block */
if (ab->sel)
glColor4fv(sel_color);
else
glColor4fv(unsel_color);
glRectf(ab->start, ypos - iconsize, ab->end, ypos + iconsize);
if (ab->flag & ACTKEYBLOCK_FLAG_MOVING_HOLD) {
/* draw "moving hold" long-keyframe block - slightly smaller */
if (ab->sel)
glColor4fv(sel_mhcol);
else
glColor4fv(unsel_mhcol);
glRectf(ab->start, ypos - mhsize, ab->end, ypos + mhsize);
}
else {
/* draw standard long-keyframe block */
if (ab->sel)
glColor4fv(sel_color);
else
glColor4fv(unsel_color);
glRectf(ab->start, ypos - iconsize, ab->end, ypos + iconsize);
}
}
}
}

View File

@ -1208,6 +1208,13 @@ static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
return 0;
}
static short set_keytype_moving_hold(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
{
if (bezt->f2 & SELECT)
BEZKEYTYPE(bezt) = BEZT_KEYTYPE_MOVEHOLD;
return 0;
}
/* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
KeyframeEditFunc ANIM_editkeyframes_keytype(short code)
{
@ -1221,6 +1228,9 @@ KeyframeEditFunc ANIM_editkeyframes_keytype(short code)
case BEZT_KEYTYPE_JITTER: /* jitter keyframe */
return set_keytype_jitter;
case BEZT_KEYTYPE_MOVEHOLD: /* moving hold */
return set_keytype_moving_hold;
case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */
default:
return set_keytype_keyframe;

View File

@ -80,7 +80,7 @@ typedef struct ActKeyBlock {
/* key-block info */
char sel;
short handle_type;
short flag;
float val;
float start, end;
@ -89,6 +89,12 @@ typedef struct ActKeyBlock {
short totcurve;
} ActKeyBlock;
/* ActKeyBlock - Flag */
typedef enum eActKeyBlock_Flag {
/* Key block represents a moving hold */
ACTKEYBLOCK_FLAG_MOVING_HOLD = (1 << 0),
} eActKeyBlock_Flag;
/* *********************** Keyframe Drawing ****************************** */
/* options for keyframe shape drawing */

View File

@ -1020,6 +1020,7 @@ DEF_VICO(KEYTYPE_KEYFRAME_VEC)
DEF_VICO(KEYTYPE_BREAKDOWN_VEC)
DEF_VICO(KEYTYPE_EXTREME_VEC)
DEF_VICO(KEYTYPE_JITTER_VEC)
DEF_VICO(KEYTYPE_MOVING_HOLD_VEC)
DEF_VICO(COLORSET_01_VEC)
DEF_VICO(COLORSET_02_VEC)

View File

@ -347,6 +347,8 @@ void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3])
// get four color values, scaled to 0.0-1.0 range
void UI_GetThemeColor4fv(int colorid, float col[4]);
// get four color values, range 0.0-1.0, complete with shading offset for the RGB components
void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4]);
// get the 3 or 4 byte values
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3]);

View File

@ -505,6 +505,11 @@ static void vicon_keytype_jitter_draw(int x, int y, int w, int h, float alpha)
vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_JITTER);
}
static void vicon_keytype_moving_hold_draw(int x, int y, int w, int h, float alpha)
{
vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_MOVEHOLD);
}
static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNUSED(alpha))
{
bTheme *btheme = UI_GetTheme();
@ -792,6 +797,7 @@ static void init_internal_icons(void)
def_internal_vicon(VICO_KEYTYPE_BREAKDOWN_VEC, vicon_keytype_breakdown_draw);
def_internal_vicon(VICO_KEYTYPE_EXTREME_VEC, vicon_keytype_extreme_draw);
def_internal_vicon(VICO_KEYTYPE_JITTER_VEC, vicon_keytype_jitter_draw);
def_internal_vicon(VICO_KEYTYPE_MOVING_HOLD_VEC, vicon_keytype_moving_hold_draw);
def_internal_vicon(VICO_COLORSET_01_VEC, vicon_colorset_draw_01);
def_internal_vicon(VICO_COLORSET_02_VEC, vicon_colorset_draw_02);

View File

@ -1473,6 +1473,30 @@ void UI_GetThemeColor3ubv(int colorid, unsigned char col[3])
col[2] = cp[2];
}
/* get the color, range 0.0-1.0, complete with shading offset */
void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4])
{
int r, g, b, a;
const unsigned char *cp;
cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
r = offset + (int) cp[0];
CLAMP(r, 0, 255);
g = offset + (int) cp[1];
CLAMP(g, 0, 255);
b = offset + (int) cp[2];
CLAMP(b, 0, 255);
a = (int) cp[3]; /* no shading offset... */
CLAMP(a, 0, 255);
col[0] = ((float)r) / 255.0f;
col[1] = ((float)g) / 255.0f;
col[2] = ((float)b) / 255.0f;
col[3] = ((float)a) / 255.0f;
}
/* get the color, in char pointer */
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
{

View File

@ -424,6 +424,7 @@ typedef enum eBezTriple_KeyframeType {
BEZT_KEYTYPE_EXTREME = 1, /* 'extreme' keyframe */
BEZT_KEYTYPE_BREAKDOWN = 2, /* 'breakdown' keyframe */
BEZT_KEYTYPE_JITTER = 3, /* 'jitter' keyframe (for adding 'filler' secondary motion) */
BEZT_KEYTYPE_MOVEHOLD = 4, /* one end of a 'moving hold' */
} eBezTriple_KeyframeType;
/* checks if the given BezTriple is selected */

View File

@ -72,6 +72,7 @@ EnumPropertyItem rna_enum_fmodifier_type_items[] = {
EnumPropertyItem rna_enum_beztriple_keyframe_type_items[] = {
{BEZT_KEYTYPE_KEYFRAME, "KEYFRAME", VICO_KEYTYPE_KEYFRAME_VEC, "Keyframe", "Normal keyframe - e.g. for key poses"},
{BEZT_KEYTYPE_BREAKDOWN, "BREAKDOWN", VICO_KEYTYPE_BREAKDOWN_VEC, "Breakdown", "A breakdown pose - e.g. for transitions between key poses"},
{BEZT_KEYTYPE_MOVEHOLD, "MOVING_HOLD", VICO_KEYTYPE_MOVING_HOLD_VEC, "Moving Hold", "A keyframe that is part of a moving hold"},
{BEZT_KEYTYPE_EXTREME, "EXTREME", VICO_KEYTYPE_EXTREME_VEC, "Extreme", "An 'extreme' pose, or some other purpose as needed"},
{BEZT_KEYTYPE_JITTER, "JITTER", VICO_KEYTYPE_JITTER_VEC, "Jitter", "A filler or baked keyframe for keying on ones, or some other purpose as needed"},
{0, NULL, 0, NULL, NULL}