Dopesheet: Added "Moving Hold" as a keyframe type
authorJoshua Leung <aligorith@gmail.com>
Thu, 7 Jul 2016 11:37:15 +0000 (23:37 +1200)
committerJoshua Leung <aligorith@gmail.com>
Thu, 7 Jul 2016 13:49:25 +0000 (01:49 +1200)
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.

source/blender/editors/animation/keyframes_draw.c
source/blender/editors/animation/keyframes_edit.c
source/blender/editors/include/ED_keyframes_draw.h
source/blender/editors/include/UI_icons.h
source/blender/editors/include/UI_resources.h
source/blender/editors/interface/interface_icons.c
source/blender/editors/interface/resources.c
source/blender/makesdna/DNA_curve_types.h
source/blender/makesrna/intern/rna_fcurve.c

index 4ec2cb2ba374ac9da052f3435269fd1fc0310da2..6e77695335616c10409405dfa40e28a71c2698c1 100644 (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);
+                               }
                        }
                }
        }
index 7b35a154fc84752636f5447d1294c48db366874d..4571df0f077c8761601c9b691ed042ffe6033d9c 100644 (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;
index 43264a6edaac6554c1ef46ff33a98153fc44fa89..b1f3f012e09ca12501a6ae86336248515899c034 100644 (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 */
index 2c80701bf69c560805499f1a52bb15a5ad269877..d85b60dcc435e068904e65a9573b6be06c3f2950 100644 (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)
index dc8439522293ff48710f66ee1abbda0ab7e971e8..a81221ed54ba78f6b29d2dddf1a0ba4b4ce08910 100644 (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]);
index 6dc60f1d70b1270cd1befe9de26038413127d1d8..e00d8cf7c072f4e0da375f39eb69dd12c33ff912 100644 (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);
index a9607d93672547875b123f23bfccfcf4e967230e..c8ff335f2a025cb66bb5957b10b4d98f70d7ff7d 100644 (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])
 {
index 61169e4b1b1894037a8a1c794fb30d0bcf74fd51..902fa4ce9879d8e11157c209cfe33ac71513fc44 100644 (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 */
index 3043c5452c045c74c2fff4e426d11b2add516575..5fb581eb74a847cda555b797e577b098071c8924 100644 (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}