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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Gavrilov <angavrilov@gmail.com>2018-10-19 18:55:19 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2018-10-29 22:04:19 +0300
commita0dfa320cddd8396911058bae7c3a0eb52e7f2ee (patch)
tree9fbb05f44a99a83354edbfea586edbb9130b886c /source/blender
parentb18ac77df3c2eb002bd4c5ed2e6b606535cb67cc (diff)
Dope Sheet: new option to display keyframe interpolation mode and extremes.
With the new automatic handle algorithm, it is possible to do a lot of the animation via keyframes without touching the curves. It is however necessary to change the keyframe interpolation and handle types in certain cases. Currently the dopesheet/action editor allows changing the types, but does not show them in any way. To fix, add a new menu option to display this information. For handle type, it is represented using the shape of the key icons: diamond for Free, clipped diamond for Aligned, square for Vector, circle for Auto Clamp, and cirle with dot for Automatic. Non-bezier interpolation is a property of intervals between keys, so it is marked by drawing lines, similar to holds. In this initial version, only the fact of non-bezier interpolation is displayed, without distinguishing types. For summaries, the line is drawn at half alpha if not all curves in the group are non-bezier. In addition, it is sometimes helpful to know the general direction of change of the curve, and which keys are extremes. This commit also adds an option to highlight extremes, based on comparing the keyed values with adjacent keys. Half-intensity display is used for overshot bezier extremes, or non-uniform summaries. Reviewers: brecht, aligorith, billreynish Differential Revision: https://developer.blender.org/D3788
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/intern/anim.c8
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c4
-rw-r--r--source/blender/editors/animation/anim_draw.c4
-rw-r--r--source/blender/editors/animation/keyframes_draw.c296
-rw-r--r--source/blender/editors/armature/pose_lib.c2
-rw-r--r--source/blender/editors/armature/pose_slide.c4
-rw-r--r--source/blender/editors/include/ED_keyframes_draw.h66
-rw-r--r--source/blender/editors/include/UI_icons.h6
-rw-r--r--source/blender/editors/include/UI_resources.h1
-rw-r--r--source/blender/editors/interface/interface_icons.c60
-rw-r--r--source/blender/editors/interface/resources.c3
-rw-r--r--source/blender/editors/screen/screen_ops.c4
-rw-r--r--source/blender/editors/space_action/action_draw.c16
-rw-r--r--source/blender/editors/space_action/action_select.c12
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_draw.c3
-rw-r--r--source/blender/editors/space_nla/nla_draw.c11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl108
-rw-r--r--source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl81
-rw-r--r--source/blender/makesdna/DNA_action_types.h6
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_curve.c10
-rw-r--r--source/blender/makesrna/intern/rna_space.c12
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c6
24 files changed, 566 insertions, 162 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index b5e20671cac..6435fe461cc 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -28,7 +28,7 @@
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 280
-#define BLENDER_SUBVERSION 27
+#define BLENDER_SUBVERSION 28
/* Several breakages with 280, e.g. collections vs layers */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index d70f3459324..89291b158b7 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -65,8 +65,8 @@
// XXX bad level call...
extern short compare_ak_cfraPtr(void *node, void *data);
-extern void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, struct DLRBT_Tree *keys);
-extern void action_to_keylist(struct AnimData *adt, struct bAction *act, struct DLRBT_Tree *keys);
+extern void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, struct DLRBT_Tree *keys, int saction_flag);
+extern void action_to_keylist(struct AnimData *adt, struct bAction *act, struct DLRBT_Tree *keys, int saction_flag);
/* --------------------- */
/* forward declarations */
@@ -485,11 +485,11 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
bActionGroup *agrp = BKE_action_group_find_name(adt->action, mpt->pchan->name);
if (agrp) {
- agroup_to_keylist(adt, agrp, &mpt->keys);
+ agroup_to_keylist(adt, agrp, &mpt->keys, 0);
}
}
else {
- action_to_keylist(adt, adt->action, &mpt->keys);
+ action_to_keylist(adt, adt->action, &mpt->keys, 0);
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 2f98d068e7d..b622bc016f5 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -77,6 +77,10 @@ static void do_versions_theme(UserDef *userdef, bTheme *btheme)
copy_v4_v4_char(btheme->tact.keytype_movehold, U_theme_default.tact.keytype_movehold);
copy_v4_v4_char(btheme->tact.keytype_movehold_select, U_theme_default.tact.keytype_movehold_select);
}
+
+ if (!USER_VERSION_ATLEAST(280, 28)) {
+ copy_v4_v4_char(btheme->tact.ds_ipoline, U_theme_default.tact.ds_ipoline);
+ }
#undef USER_VERSION_ATLEAST
}
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 48dd310e2b4..a2046985a36 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -551,11 +551,11 @@ static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prev
}
/* populate tree with keyframe nodes */
- scene_to_keylist(&ads, scene, &keys);
+ scene_to_keylist(&ads, scene, &keys, 0);
gpencil_to_keylist(&ads, scene->gpd, &keys, false);
if (ob) {
- ob_to_keylist(&ads, ob, &keys);
+ ob_to_keylist(&ads, ob, &keys, 0);
gpencil_to_keylist(&ads, ob->data, &keys, false);
}
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 33e2a11f4c5..008160e2459 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -42,6 +42,7 @@
#include "BLI_dlrbTree.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_rect.h"
#include "DNA_anim_types.h"
#include "DNA_cachefile_types.h"
@@ -96,24 +97,108 @@ short compare_ak_cfraPtr(void *node, void *data)
/* --------------- */
-/* Comparator callback used for ActKeyColumns and BezTriple */
+/* 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;
+ }
+ else if (ELEM(bezt->h1, HD_AUTO_ANIM, HD_AUTO) && ELEM(bezt->h2, HD_AUTO_ANIM, HD_AUTO)) {
+ return KEYFRAME_HANDLE_AUTO;
+ }
+ else if (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) {
+ return KEYFRAME_HANDLE_VECTOR;
+ }
+ else if (ELEM(HD_FREE, bezt->h1, bezt->h2)) {
+ return KEYFRAME_HANDLE_FREE;
+ }
+ else {
+ 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)
{
- BezTriple *bezt = (BezTriple *)data;
+ BezTripleChain *chain = (BezTripleChain*)data;
- return compare_ak_cfraPtr(node, &bezt->vec[1][0]);
+ return compare_ak_cfraPtr(node, &chain->cur->vec[1][0]);
}
-/* New node callback used for building ActKeyColumns from BezTriples */
+/* New node callback used for building ActKeyColumns from BezTripleChain */
static DLRBT_Node *nalloc_ak_bezt(void *data)
{
ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
- BezTriple *bezt = (BezTriple *)data;
+ BezTripleChain *chain = (BezTripleChain*)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;
@@ -121,11 +206,12 @@ static DLRBT_Node *nalloc_ak_bezt(void *data)
return (DLRBT_Node *)ak;
}
-/* Node updater callback used for building ActKeyColumns from BezTriples */
+/* Node updater callback used for building ActKeyColumns from BezTripleChain */
static void nupdate_ak_bezt(void *node, void *data)
{
ActKeyColumn *ak = (ActKeyColumn *)node;
- BezTriple *bezt = (BezTriple *)data;
+ BezTripleChain *chain = (BezTripleChain*)data;
+ BezTriple *bezt = chain->cur;
/* set selection status and 'touched' status */
if (BEZT_ISSEL_ANY(bezt)) ak->sel = SELECT;
@@ -136,6 +222,22 @@ static void nupdate_ak_bezt(void *node, void *data)
/* 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);
+ }
+ }
}
/* ......... */
@@ -225,7 +327,7 @@ static void nupdate_ak_masklayshape(void *node, void *data)
/* --------------- */
/* Add the given BezTriple to the given 'list' of Keyframes */
-static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTriple *bezt)
+static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTripleChain *bezt)
{
if (ELEM(NULL, keys, bezt))
return;
@@ -291,6 +393,11 @@ static void compute_keyblock_data(ActKeyBlockInfo *info, BezTriple *prev, BezTri
}
}
+ /* 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);
}
@@ -410,11 +517,16 @@ static void update_keyblocks(DLRBT_Tree *keys, BezTriple *bezt, int 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 (ac == NULL || ac->next == NULL || ac->totblock == 0)
+ if (!actkeyblock_is_valid(ac))
return 0;
const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD);
@@ -424,7 +536,8 @@ int actkeyblock_get_valid_hold(ActKeyColumn *ac)
/* *************************** Keyframe Drawing *************************** */
void draw_keyframe_shape(float x, float y, float size, bool sel, short key_type, short mode, float alpha,
- unsigned int pos_id, unsigned int size_id, unsigned int color_id, unsigned int outline_color_id)
+ unsigned int pos_id, unsigned int size_id, unsigned int color_id, unsigned int outline_color_id,
+ unsigned int flags_id, short handle_type, short extreme_type)
{
bool draw_fill = ELEM(mode, KEYFRAME_SHAPE_INSIDE, KEYFRAME_SHAPE_BOTH);
bool draw_outline = ELEM(mode, KEYFRAME_SHAPE_FRAME, KEYFRAME_SHAPE_BOTH);
@@ -456,6 +569,7 @@ void draw_keyframe_shape(float x, float y, float size, bool sel, short key_type,
unsigned char fill_col[4];
unsigned char outline_col[4];
+ unsigned int flags = 0;
/* draw! */
if (draw_fill) {
@@ -504,19 +618,44 @@ void draw_keyframe_shape(float x, float y, float size, bool sel, short key_type,
fill_col[2] = outline_col[2];
fill_col[3] = 0;
}
+
+ /* Handle type to outline shape. */
+ switch (handle_type) {
+ case KEYFRAME_HANDLE_AUTO_CLAMP: flags = 0x2; break; /* circle */
+ case KEYFRAME_HANDLE_AUTO: flags = 0x12; break; /* circle with dot */
+ case KEYFRAME_HANDLE_VECTOR: flags = 0xC; break; /* square */
+ case KEYFRAME_HANDLE_ALIGNED: flags = 0x5; break; /* clipped diamond */
+
+ case KEYFRAME_HANDLE_FREE:
+ default:
+ flags = 1; /* diamond */
+ }
+
+ /* Extreme type to arrow-like shading. */
+ if (extreme_type & KEYFRAME_EXTREME_MAX) {
+ flags |= 0x100;
+ }
+ if (extreme_type & KEYFRAME_EXTREME_MIN) {
+ flags |= 0x200;
+ }
+ if (extreme_type & KEYFRAME_EXTREME_MIXED) {
+ flags |= 0x400;
+ }
}
immAttr1f(size_id, size);
immAttr4ubv(color_id, fill_col);
immAttr4ubv(outline_color_id, outline_col);
+ immAttr1u(flags_id, flags);
immVertex2f(pos_id, x, y);
}
-static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, float ypos, float yscale_fac, bool channelLocked)
+static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, float ypos, float yscale_fac, bool channelLocked, int saction_flag)
{
const float icon_sz = U.widget_unit * 0.5f * yscale_fac;
const float half_icon_sz = 0.5f * icon_sz;
const float smaller_sz = 0.35f * icon_sz;
+ const float ipo_sz = 0.1f * icon_sz;
GPU_blend(true);
@@ -524,28 +663,39 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, float ypos, float yscale
/* TODO: allow this opacity factor to be themed? */
float alpha = channelLocked ? 0.25f : 1.0f;
+ /* Show interpolation and handle type? */
+ bool show_ipo = (saction_flag & SACTION_SHOW_INTERPOLATION) != 0;
+
/* draw keyblocks */
if (keys) {
float sel_color[4], unsel_color[4];
float sel_mhcol[4], unsel_mhcol[4];
+ float ipo_color[4], ipo_color_mix[4];
/* cache colours first */
UI_GetThemeColor4fv(TH_STRIP_SELECT, sel_color);
UI_GetThemeColor4fv(TH_STRIP, unsel_color);
+ UI_GetThemeColor4fv(TH_DOPESHEET_IPOLINE, ipo_color);
sel_color[3] *= alpha;
unsel_color[3] *= alpha;
+ ipo_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;
+ copy_v4_v4(ipo_color_mix, ipo_color);
+ ipo_color_mix[3] *= 0.5f;
uint block_len = 0;
for (ActKeyColumn *ab = keys->first; ab; ab = ab->next) {
if (actkeyblock_get_valid_hold(ab)) {
block_len++;
}
+ if (show_ipo && actkeyblock_is_valid(ab) && (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) {
+ block_len++;
+ }
}
if (block_len > 0) {
@@ -571,6 +721,12 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, float ypos, float yscale
(ab->block.sel) ? sel_color : unsel_color);
}
}
+ if (show_ipo && actkeyblock_is_valid(ab) && (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) {
+ /* draw an interpolation line */
+ immRectf_fast_with_color(pos_id, color_id,
+ ab->cfra, ypos - ipo_sz, ab->next->cfra, ypos + ipo_sz,
+ (ab->block.conflict & ACTKEYBLOCK_FLAG_NON_BEZIER) ? ipo_color_mix : ipo_color);
+ }
}
immEnd();
immUnbindProgram();
@@ -595,14 +751,25 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, float ypos, float yscale
uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
uint outline_color_id = GPU_vertformat_attr_add(format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
GPU_enable_program_point_size();
+ immUniform2f("ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1);
immBegin(GPU_PRIM_POINTS, key_len);
+ short handle_type = KEYFRAME_HANDLE_NONE, extreme_type = KEYFRAME_EXTREME_NONE;
+
for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) {
if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) {
+ if (show_ipo) {
+ handle_type = ak->handle_type;
+ }
+ if (saction_flag & SACTION_SHOW_EXTREMES) {
+ extreme_type = ak->extreme_type;
+ }
+
draw_keyframe_shape(ak->cfra, ypos, icon_sz, (ak->sel & SELECT), ak->key_type, KEYFRAME_SHAPE_BOTH, alpha,
- pos_id, size_id, color_id, outline_color_id);
+ pos_id, size_id, color_id, outline_color_id, flags_id, handle_type, extreme_type);
}
}
@@ -617,46 +784,52 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, float ypos, float yscale
/* *************************** Channel Drawing Funcs *************************** */
-void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos, float yscale_fac)
+void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos, float yscale_fac, int saction_flag)
{
DLRBT_Tree keys;
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
+
BLI_dlrbTree_init(&keys);
- summary_to_keylist(ac, &keys);
+ summary_to_keylist(ac, &keys, saction_flag);
- draw_keylist(v2d, &keys, ypos, yscale_fac, false);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
BLI_dlrbTree_free(&keys);
}
-void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos, float yscale_fac)
+void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos, float yscale_fac, int saction_flag)
{
DLRBT_Tree keys;
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
+
BLI_dlrbTree_init(&keys);
- scene_to_keylist(ads, sce, &keys);
+ scene_to_keylist(ads, sce, &keys, saction_flag);
- draw_keylist(v2d, &keys, ypos, yscale_fac, false);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
BLI_dlrbTree_free(&keys);
}
-void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos, float yscale_fac)
+void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos, float yscale_fac, int saction_flag)
{
DLRBT_Tree keys;
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
+
BLI_dlrbTree_init(&keys);
- ob_to_keylist(ads, ob, &keys);
+ ob_to_keylist(ads, ob, &keys, saction_flag);
- draw_keylist(v2d, &keys, ypos, yscale_fac, false);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
BLI_dlrbTree_free(&keys);
}
-void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos, float yscale_fac)
+void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos, float yscale_fac, int saction_flag)
{
DLRBT_Tree keys;
@@ -666,14 +839,14 @@ void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos, fl
BLI_dlrbTree_init(&keys);
- fcurve_to_keylist(adt, fcu, &keys);
+ fcurve_to_keylist(adt, fcu, &keys, saction_flag);
- draw_keylist(v2d, &keys, ypos, yscale_fac, locked);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
BLI_dlrbTree_free(&keys);
}
-void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos, float yscale_fac)
+void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos, float yscale_fac, int saction_flag)
{
DLRBT_Tree keys;
@@ -682,42 +855,46 @@ void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float y
BLI_dlrbTree_init(&keys);
- agroup_to_keylist(adt, agrp, &keys);
+ agroup_to_keylist(adt, agrp, &keys, saction_flag);
- draw_keylist(v2d, &keys, ypos, yscale_fac, locked);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
BLI_dlrbTree_free(&keys);
}
-void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos, float yscale_fac)
+void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos, float yscale_fac, int saction_flag)
{
DLRBT_Tree keys;
bool locked = (act && ID_IS_LINKED(act));
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
+
BLI_dlrbTree_init(&keys);
- action_to_keylist(adt, act, &keys);
+ action_to_keylist(adt, act, &keys, saction_flag);
- draw_keylist(v2d, &keys, ypos, yscale_fac, locked);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
BLI_dlrbTree_free(&keys);
}
-void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos, float yscale_fac)
+void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos, float yscale_fac, int saction_flag)
{
DLRBT_Tree keys;
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
+
BLI_dlrbTree_init(&keys);
gpencil_to_keylist(ads, gpd, &keys, false);
- draw_keylist(v2d, &keys, ypos, yscale_fac, false);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
BLI_dlrbTree_free(&keys);
}
-void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos, float yscale_fac)
+void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos, float yscale_fac, int saction_flag)
{
DLRBT_Tree keys;
@@ -727,12 +904,12 @@ void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos,
gpl_to_keylist(ads, gpl, &keys);
- draw_keylist(v2d, &keys, ypos, yscale_fac, locked);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
BLI_dlrbTree_free(&keys);
}
-void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, float ypos, float yscale_fac)
+void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, float ypos, float yscale_fac, int saction_flag)
{
DLRBT_Tree keys;
@@ -742,14 +919,14 @@ void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, floa
mask_to_keylist(ads, masklay, &keys);
- draw_keylist(v2d, &keys, ypos, yscale_fac, locked);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
BLI_dlrbTree_free(&keys);
}
/* *************************** Keyframe List Conversions *************************** */
-void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys)
+void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, int saction_flag)
{
if (ac) {
ListBase anim_data = {NULL, NULL};
@@ -769,7 +946,7 @@ void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys)
switch (ale->datatype) {
case ALE_FCURVE:
- fcurve_to_keylist(ale->adt, ale->data, keys);
+ fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
break;
case ALE_MASKLAY:
mask_to_keylist(ac->ads, ale->data, keys);
@@ -787,7 +964,7 @@ void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys)
}
}
-void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys)
+void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, int saction_flag)
{
bAnimContext ac = {NULL};
ListBase anim_data = {NULL, NULL};
@@ -815,12 +992,12 @@ void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys)
/* 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);
+ 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)
+void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, int saction_flag)
{
bAnimContext ac = {NULL};
ListBase anim_data = {NULL, NULL};
@@ -851,12 +1028,12 @@ void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys)
/* 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);
+ 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)
+void cachefile_to_keylist(bDopeSheet *ads, CacheFile *cache_file, DLRBT_Tree *keys, int saction_flag)
{
if (cache_file == NULL) {
return;
@@ -881,25 +1058,36 @@ void cachefile_to_keylist(bDopeSheet *ads, CacheFile *cache_file, DLRBT_Tree *ke
/* loop through each F-Curve, grabbing the keyframes */
for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
- fcurve_to_keylist(ale->adt, ale->data, keys);
+ 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)
+void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, int saction_flag)
{
- BezTriple *bezt;
- unsigned int v;
-
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 */
- for (v = 0, bezt = fcu->bezt; v < fcu->totvert; v++, bezt++) {
- add_bezt_to_keycolumns_list(keys, bezt);
+ 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. */
@@ -911,26 +1099,26 @@ void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys)
}
}
-void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, DLRBT_Tree *keys)
+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);
+ fcurve_to_keylist(adt, fcu, keys, saction_flag);
}
}
}
-void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys)
+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);
+ fcurve_to_keylist(adt, fcu, keys, saction_flag);
}
}
}
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 673ca587811..280aa73b1c8 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -312,7 +312,7 @@ static int poselib_sanitize_exec(bContext *C, wmOperator *op)
/* determine which frames have keys */
BLI_dlrbTree_init(&keys);
- action_to_keylist(NULL, act, &keys);
+ action_to_keylist(NULL, act, &keys, 0);
/* for each key, make sure there is a corresponding pose */
for (ak = keys.first; ak; ak = ak->next) {
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index bae794e84c4..be3914b2054 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -789,7 +789,7 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
/* do this for each F-Curve */
for (ld = pfl->fcurves.first; ld; ld = ld->next) {
FCurve *fcu = (FCurve *)ld->data;
- fcurve_to_keylist(pfl->ob->adt, fcu, &pso->keys);
+ fcurve_to_keylist(pfl->ob->adt, fcu, &pso->keys, 0);
}
}
@@ -1350,7 +1350,7 @@ static float pose_propagate_get_boneHoldEndFrame(tPChanFCurveLink *pfl, float st
for (ld = pfl->fcurves.first; ld; ld = ld->next) {
FCurve *fcu = (FCurve *)ld->data;
- fcurve_to_keylist(adt, fcu, &keys);
+ fcurve_to_keylist(adt, fcu, &keys, 0);
}
/* find the long keyframe (i.e. hold), and hence obtain the endFrame value
diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h
index 93fd8238fdd..6421c5817b0 100644
--- a/source/blender/editors/include/ED_keyframes_draw.h
+++ b/source/blender/editors/include/ED_keyframes_draw.h
@@ -73,6 +73,8 @@ typedef struct ActKeyColumn {
/* keyframe info */
char key_type; /* eBezTripe_KeyframeType */
+ char handle_type; /* eKeyframeHandleDrawOpts */
+ char extreme_type; /* eKeyframeExtremeDrawOpts */
short sel;
float cfra;
@@ -91,6 +93,8 @@ typedef enum eActKeyBlock_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),
} eActKeyBlock_Flag;
/* *********************** Keyframe Drawing ****************************** */
@@ -105,48 +109,73 @@ typedef enum eKeyframeShapeDrawOpts {
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 neigbors 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 */
void draw_keyframe_shape(float x, float y, float size, bool sel, short key_type, short mode, float alpha,
- unsigned int pos_id, unsigned int size_id, unsigned int color_id, unsigned int outline_color_id);
+ unsigned int pos_id, unsigned int size_id, unsigned int color_id, unsigned int outline_color_id,
+ unsigned int linemask_id, short ipo_type, short extreme_type);
/* ******************************* Methods ****************************** */
/* Channel Drawing ------------------ */
/* F-Curve */
-void draw_fcurve_channel(struct View2D *v2d, struct AnimData *adt, struct FCurve *fcu, float ypos, float yscale_fac);
+void draw_fcurve_channel(struct View2D *v2d, struct AnimData *adt, struct FCurve *fcu, float ypos, float yscale_fac, int saction_flag);
/* Action Group Summary */
-void draw_agroup_channel(struct View2D *v2d, struct AnimData *adt, struct bActionGroup *agrp, float ypos, float yscale_fac);
+void draw_agroup_channel(struct View2D *v2d, struct AnimData *adt, struct bActionGroup *agrp, float ypos, float yscale_fac, int saction_flag);
/* Action Summary */
-void draw_action_channel(struct View2D *v2d, struct AnimData *adt, struct bAction *act, float ypos, float yscale_fac);
+void draw_action_channel(struct View2D *v2d, struct AnimData *adt, struct bAction *act, float ypos, float yscale_fac, int saction_flag);
/* Object Summary */
-void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Object *ob, float ypos, float yscale_fac);
+void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Object *ob, float ypos, float yscale_fac, int saction_flag);
/* Scene Summary */
-void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos, float yscale_fac);
+void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos, float yscale_fac, int saction_flag);
/* DopeSheet Summary */
-void draw_summary_channel(struct View2D *v2d, struct bAnimContext *ac, float ypos, float yscale_fac);
+void draw_summary_channel(struct View2D *v2d, struct bAnimContext *ac, float ypos, float yscale_fac, int saction_flag);
/* Grease Pencil datablock summary */
-void draw_gpencil_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPdata *gpd, float ypos, float yscale_fac);
+void draw_gpencil_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPdata *gpd, float ypos, float yscale_fac, int saction_flag);
/* Grease Pencil Layer */
-void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos, float yscale_fac);
+void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos, float yscale_fac, int saction_flag);
/* Mask Layer */
-void draw_masklay_channel(struct View2D *v2d, struct bDopeSheet *ads, struct MaskLayer *masklay, float ypos, float yscale_fac);
+void draw_masklay_channel(struct View2D *v2d, struct bDopeSheet *ads, struct MaskLayer *masklay, float ypos, float yscale_fac, int saction_flag);
/* Keydata Generation --------------- */
/* F-Curve */
-void fcurve_to_keylist(struct AnimData *adt, struct FCurve *fcu, struct DLRBT_Tree *keys);
+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);
+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);
+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);
+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);
+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);
+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);
+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 */
@@ -160,6 +189,9 @@ void mask_to_keylist(struct bDopeSheet *UNUSED(ads), struct MaskLayer *masklay,
/* 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 *ab);
+
/* Checks if ActKeyColumn can be used as a block (i.e. drawn/used to detect "holds") */
int actkeyblock_get_valid_hold(ActKeyColumn *ab);
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index b5e910a650a..cde88e13b1f 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -982,6 +982,12 @@ DEF_ICON_VECTOR(KEYTYPE_EXTREME_VEC)
DEF_ICON_VECTOR(KEYTYPE_JITTER_VEC)
DEF_ICON_VECTOR(KEYTYPE_MOVING_HOLD_VEC)
+DEF_ICON_VECTOR(HANDLETYPE_FREE_VEC)
+DEF_ICON_VECTOR(HANDLETYPE_ALIGNED_VEC)
+DEF_ICON_VECTOR(HANDLETYPE_VECTOR_VEC)
+DEF_ICON_VECTOR(HANDLETYPE_AUTO_VEC)
+DEF_ICON_VECTOR(HANDLETYPE_AUTO_CLAMP_VEC)
+
DEF_ICON_VECTOR(COLORSET_01_VEC)
DEF_ICON_VECTOR(COLORSET_02_VEC)
DEF_ICON_VECTOR(COLORSET_03_VEC)
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index fd6fa3add30..277aae923d6 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -217,6 +217,7 @@ typedef enum ThemeColorID {
TH_DOPESHEET_CHANNELOB,
TH_DOPESHEET_CHANNELSUBOB,
+ TH_DOPESHEET_IPOLINE,
TH_PREVIEW_BACK,
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 6289bc09f5a..09e16b806f3 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -286,7 +286,7 @@ static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float
immUnbindProgram();
}
-static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha, short key_type)
+static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha, short key_type, short handle_type)
{
/* init dummy theme state for Action Editor - where these colors are defined
* (since we're doing this offscreen, free from any particular space_id)
@@ -300,25 +300,30 @@ static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha,
* while the draw_keyframe_shape() function needs the midpoint for
* the keyframe
*/
- int xco = x + w / 2;
- int yco = y + h / 2;
+ float xco = x + w / 2 + 0.5f;
+ float yco = y + h / 2 + 0.5f;
GPUVertFormat *format = immVertexFormat();
uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
uint outline_color_id = GPU_vertformat_attr_add(format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
GPU_enable_program_point_size();
+ immUniform2f("ViewportSize", -1.0f, -1.0f);
immBegin(GPU_PRIM_POINTS, 1);
/* draw keyframe
- * - size: 0.6 * h (found out experimentally... dunno why!)
- * - sel: true (so that "keyframe" state shows the iconic yellow icon)
+ * - size: (default icon size == 16, default dopesheet icon size == 10)
+ * - sel: true unless in handletype icons (so that "keyframe" state shows the iconic yellow icon)
*/
- draw_keyframe_shape(xco, yco, 0.6f * h, true, key_type, KEYFRAME_SHAPE_BOTH, alpha,
- pos_id, size_id, color_id, outline_color_id);
+ bool sel = (handle_type == KEYFRAME_HANDLE_NONE);
+
+ draw_keyframe_shape(xco, yco, (10.0f / 16.0f) * h, sel, key_type, KEYFRAME_SHAPE_BOTH, alpha,
+ pos_id, size_id, color_id, outline_color_id,
+ flags_id, handle_type, KEYFRAME_EXTREME_NONE);
immEnd();
GPU_disable_program_point_size();
@@ -329,27 +334,52 @@ static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha,
static void vicon_keytype_keyframe_draw(int x, int y, int w, int h, float alpha)
{
- vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME);
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_NONE);
}
static void vicon_keytype_breakdown_draw(int x, int y, int w, int h, float alpha)
{
- vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_BREAKDOWN);
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_BREAKDOWN, KEYFRAME_HANDLE_NONE);
}
static void vicon_keytype_extreme_draw(int x, int y, int w, int h, float alpha)
{
- vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_EXTREME);
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_EXTREME, KEYFRAME_HANDLE_NONE);
}
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);
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_JITTER, KEYFRAME_HANDLE_NONE);
}
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);
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_MOVEHOLD, KEYFRAME_HANDLE_NONE);
+}
+
+static void vicon_handletype_free_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_FREE);
+}
+
+static void vicon_handletype_aligned_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_ALIGNED);
+}
+
+static void vicon_handletype_vector_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_VECTOR);
+}
+
+static void vicon_handletype_auto_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_AUTO);
+}
+
+static void vicon_handletype_auto_clamp_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_AUTO_CLAMP);
}
static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNUSED(alpha))
@@ -770,6 +800,12 @@ static void init_internal_icons(void)
def_internal_vicon(ICON_KEYTYPE_JITTER_VEC, vicon_keytype_jitter_draw);
def_internal_vicon(ICON_KEYTYPE_MOVING_HOLD_VEC, vicon_keytype_moving_hold_draw);
+ def_internal_vicon(ICON_HANDLETYPE_FREE_VEC, vicon_handletype_free_draw);
+ def_internal_vicon(ICON_HANDLETYPE_ALIGNED_VEC, vicon_handletype_aligned_draw);
+ def_internal_vicon(ICON_HANDLETYPE_VECTOR_VEC, vicon_handletype_vector_draw);
+ def_internal_vicon(ICON_HANDLETYPE_AUTO_VEC, vicon_handletype_auto_draw);
+ def_internal_vicon(ICON_HANDLETYPE_AUTO_CLAMP_VEC, vicon_handletype_auto_clamp_draw);
+
def_internal_vicon(ICON_COLORSET_01_VEC, vicon_colorset_draw_01);
def_internal_vicon(ICON_COLORSET_02_VEC, vicon_colorset_draw_02);
def_internal_vicon(ICON_COLORSET_03_VEC, vicon_colorset_draw_03);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 220d7064a5d..0ac534e5fcf 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -548,6 +548,9 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
case TH_DOPESHEET_CHANNELSUBOB:
cp = ts->ds_subchannel;
break;
+ case TH_DOPESHEET_IPOLINE:
+ cp = ts->ds_ipoline;
+ break;
case TH_PREVIEW_BACK:
cp = ts->preview_back;
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 44c2d3191e6..e570340698f 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -2627,10 +2627,10 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
}
/* populate tree with keyframe nodes */
- scene_to_keylist(&ads, scene, &keys);
+ scene_to_keylist(&ads, scene, &keys, 0);
if (ob) {
- ob_to_keylist(&ads, ob, &keys);
+ ob_to_keylist(&ads, ob, &keys, 0);
if (ob->type == OB_GPENCIL) {
const bool active = !(scene->flag & SCE_KEYS_NO_SELONLY);
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 3ea3d067216..ef2694ec70a 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -357,28 +357,28 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
/* draw 'keyframes' for each specific datatype */
switch (ale->datatype) {
case ALE_ALL:
- draw_summary_channel(v2d, ale->data, y, ac->yscale_fac);
+ draw_summary_channel(v2d, ale->data, y, ac->yscale_fac, saction->flag);
break;
case ALE_SCE:
- draw_scene_channel(v2d, ads, ale->key_data, y, ac->yscale_fac);
+ draw_scene_channel(v2d, ads, ale->key_data, y, ac->yscale_fac, saction->flag);
break;
case ALE_OB:
- draw_object_channel(v2d, ads, ale->key_data, y, ac->yscale_fac);
+ draw_object_channel(v2d, ads, ale->key_data, y, ac->yscale_fac, saction->flag);
break;
case ALE_ACT:
- draw_action_channel(v2d, adt, ale->key_data, y, ac->yscale_fac);
+ draw_action_channel(v2d, adt, ale->key_data, y, ac->yscale_fac, saction->flag);
break;
case ALE_GROUP:
- draw_agroup_channel(v2d, adt, ale->data, y, ac->yscale_fac);
+ draw_agroup_channel(v2d, adt, ale->data, y, ac->yscale_fac, saction->flag);
break;
case ALE_FCURVE:
- draw_fcurve_channel(v2d, adt, ale->key_data, y, ac->yscale_fac);
+ draw_fcurve_channel(v2d, adt, ale->key_data, y, ac->yscale_fac, saction->flag);
break;
case ALE_GPFRAME:
- draw_gpl_channel(v2d, ads, ale->data, y, ac->yscale_fac);
+ draw_gpl_channel(v2d, ads, ale->data, y, ac->yscale_fac, saction->flag);
break;
case ALE_MASKLAY:
- draw_masklay_channel(v2d, ads, ale->data, y, ac->yscale_fac);
+ draw_masklay_channel(v2d, ads, ale->data, y, ac->yscale_fac, saction->flag);
break;
}
}
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 59211ba01d7..c00be5f4c39 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -1449,37 +1449,37 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
case ALE_SCE:
{
Scene *scene = (Scene *)ale->key_data;
- scene_to_keylist(ads, scene, &anim_keys);
+ scene_to_keylist(ads, scene, &anim_keys, 0);
break;
}
case ALE_OB:
{
Object *ob = (Object *)ale->key_data;
- ob_to_keylist(ads, ob, &anim_keys);
+ ob_to_keylist(ads, ob, &anim_keys, 0);
break;
}
case ALE_ACT:
{
bAction *act = (bAction *)ale->key_data;
- action_to_keylist(adt, act, &anim_keys);
+ action_to_keylist(adt, act, &anim_keys, 0);
break;
}
case ALE_FCURVE:
{
FCurve *fcu = (FCurve *)ale->key_data;
- fcurve_to_keylist(adt, fcu, &anim_keys);
+ fcurve_to_keylist(adt, fcu, &anim_keys, 0);
break;
}
}
}
else if (ale->type == ANIMTYPE_SUMMARY) {
/* dopesheet summary covers everything */
- summary_to_keylist(ac, &anim_keys);
+ summary_to_keylist(ac, &anim_keys, 0);
}
else if (ale->type == ANIMTYPE_GROUP) {
// TODO: why don't we just give groups key_data too?
bActionGroup *agrp = (bActionGroup *)ale->data;
- agroup_to_keylist(adt, agrp, &anim_keys);
+ agroup_to_keylist(adt, agrp, &anim_keys, 0);
}
else if (ale->type == ANIMTYPE_GPLAYER) {
// TODO: why don't we just give gplayers key_data too?
diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.c b/source/blender/editors/space_clip/clip_dopesheet_draw.c
index dec7487a754..c05a4c1b64c 100644
--- a/source/blender/editors/space_clip/clip_dopesheet_draw.c
+++ b/source/blender/editors/space_clip/clip_dopesheet_draw.c
@@ -219,14 +219,17 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene)
uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
uint outline_color_id = GPU_vertformat_attr_add(format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
GPU_enable_program_point_size();
+ immUniform2f("ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1);
immBegin(GPU_PRIM_POINTS, keyframe_len);
/* all same size with black outline */
immAttr1f(size_id, 2.0f * STRIP_HEIGHT_HALF);
immAttr4ub(outline_color_id, 0, 0, 0, 255);
+ immAttr1u(flags_id, 0);
y = (float) CHANNEL_FIRST; /* start again at the top */
for (channel = dopesheet->channels.first; channel; channel = channel->next) {
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 88f2766a915..15a66b225c9 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -101,12 +101,12 @@ void nla_action_get_color(AnimData *adt, bAction *act, float color[4])
}
/* draw the keyframes in the specified Action */
-static void nla_action_draw_keyframes(AnimData *adt, bAction *act, float y, float ymin, float ymax)
+static void nla_action_draw_keyframes(View2D *v2d, AnimData *adt, bAction *act, float y, float ymin, float ymax)
{
/* get a list of the keyframes with NLA-scaling applied */
DLRBT_Tree keys;
BLI_dlrbTree_init(&keys);
- action_to_keylist(adt, act, &keys);
+ action_to_keylist(adt, act, &keys, 0);
if (ELEM(NULL, act, keys.first))
return;
@@ -145,8 +145,10 @@ static void nla_action_draw_keyframes(AnimData *adt, bAction *act, float y, floa
uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
uint outline_color_id = GPU_vertformat_attr_add(format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
GPU_enable_program_point_size();
+ immUniform2f("ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1);
immBegin(GPU_PRIM_POINTS, key_len);
/* - disregard the selection status of keyframes so they draw a certain way
@@ -154,7 +156,8 @@ static void nla_action_draw_keyframes(AnimData *adt, bAction *act, float y, floa
*/
for (ActKeyColumn *ak = keys.first; ak; ak = ak->next) {
draw_keyframe_shape(ak->cfra, y, 6.0f, false, ak->key_type, KEYFRAME_SHAPE_FRAME, 1.0f,
- pos_id, size_id, color_id, outline_color_id);
+ pos_id, size_id, color_id, outline_color_id,
+ flags_id, KEYFRAME_HANDLE_NONE, KEYFRAME_EXTREME_NONE);
}
immEnd();
@@ -750,7 +753,7 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
immUnbindProgram();
/* draw keyframes in the action */
- nla_action_draw_keyframes(adt, ale->data, y, yminc + NLACHANNEL_SKIP, ymaxc - NLACHANNEL_SKIP);
+ nla_action_draw_keyframes(v2d, adt, ale->data, y, yminc + NLACHANNEL_SKIP, ymaxc - NLACHANNEL_SKIP);
GPU_blend(false);
break;
diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl
index 7f445369833..1c12a4f942d 100644
--- a/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl
@@ -1,31 +1,87 @@
+flat in vec4 radii;
+flat in vec4 thresholds;
+
+flat in vec4 finalColor;
+flat in vec4 finalOutlineColor;
+
+flat in int finalFlags;
-in vec4 radii;
-in vec4 finalColor;
-in vec4 finalOutlineColor;
out vec4 fragColor;
+const float diagonal_scale = sqrt(0.5);
+
+const float minmax_bias = 0.7;
+const float minmax_scale = sqrt(1.0 / (1.0 + 1.0/minmax_bias));
+
+bool test(int bit) {
+ return (finalFlags & bit) != 0;
+}
+
void main() {
- vec2 quad = abs(gl_PointCoord - vec2(0.5));
- float dist = quad.x + quad.y;
-
-// transparent outside of point
-// --- 0 ---
-// smooth transition
-// --- 1 ---
-// pure outline color
-// --- 2 ---
-// smooth transition
-// --- 3 ---
-// pure point color
-// ...
-// dist = 0 at center of point
-
- float mid_stroke = 0.5 * (radii[1] + radii[2]);
-
- vec4 backgroundColor = vec4(finalOutlineColor.rgb, 0.0);
-
- if (dist > mid_stroke)
- fragColor = mix(finalOutlineColor, backgroundColor, smoothstep(radii[1], radii[0], dist));
- else
- fragColor = mix(finalColor, finalOutlineColor, smoothstep(radii[3], radii[2], dist));
+ vec2 pos = gl_PointCoord - vec2(0.5);
+ vec2 absPos = abs(pos);
+ float radius = (absPos.x + absPos.y) * diagonal_scale;
+
+ float outline_dist = -1.0;
+
+ /* Diamond outline */
+ if (test(0x1)) {
+ outline_dist = max(outline_dist, radius - radii[0]);
+ }
+
+ /* Circle outline */
+ if (test(0x2)) {
+ radius = length(absPos);
+
+ outline_dist = max(outline_dist, radius - radii[1]);
+ }
+
+ /* Top & Bottom clamp */
+ if (test(0x4)) {
+ outline_dist = max(outline_dist, absPos.y - radii[2]);
+ }
+
+ /* Left & Right clamp */
+ if (test(0x8)) {
+ outline_dist = max(outline_dist, absPos.x - radii[2]);
+ }
+
+ float alpha = 1 - smoothstep(thresholds[0], thresholds[1], abs(outline_dist));
+
+ /* Inside the outline. */
+ if (outline_dist < 0) {
+ /* Middle dot */
+ if (test(0x10)) {
+ alpha = max(alpha, 1 - smoothstep(thresholds[2], thresholds[3], radius));
+ }
+
+ /* Up and down arrow-like shading. */
+ if (test(0x300)) {
+ float ypos = -1.0;
+
+ /* Up arrow (maximum) */
+ if (test(0x100)) {
+ ypos = max(ypos, pos.y);
+ }
+ /* Down arrow (minimum) */
+ if (test(0x200)) {
+ ypos = max(ypos, -pos.y);
+ }
+
+ /* Arrow shape threshold. */
+ float minmax_dist = (ypos - radii[3]) - absPos.x * minmax_bias;
+ float minmax_step = smoothstep(thresholds[0], thresholds[1], minmax_dist * minmax_scale);
+
+ /* Reduced alpha for uncertain extremes. */
+ float minmax_alpha = test(0x400) ? 0.55 : 0.85;
+
+ alpha = max(alpha, minmax_step * minmax_alpha);
+ }
+
+ fragColor = mix(finalColor, finalOutlineColor, alpha);
+ }
+ /* Outside the outline. */
+ else {
+ fragColor = vec4(finalOutlineColor.rgb, finalOutlineColor.a * alpha);
+ }
}
diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl
index c49832bf9b4..26eb864821a 100644
--- a/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl
@@ -1,34 +1,83 @@
uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 ViewportSize = vec2(-1, -1);
-const float pixel_fudge = sqrt(2.0);
-const float outline_width = 1.15 * pixel_fudge;
+const float line_falloff = 1.0;
+const float circle_scale = sqrt(2.0 / 3.1416);
+const float square_scale = sqrt(0.5);
+
+const float diagonal_scale = sqrt(0.5);
in vec2 pos;
in float size;
in vec4 color;
in vec4 outlineColor;
-out vec4 finalColor;
-out vec4 finalOutlineColor;
-out vec4 radii;
+in int flags;
+
+flat out vec4 finalColor;
+flat out vec4 finalOutlineColor;
+
+flat out int finalFlags;
+
+flat out vec4 radii;
+flat out vec4 thresholds;
+
+bool test(int bit) {
+ return (flags & bit) != 0;
+}
+
+vec2 line_thresholds(float width) {
+ return vec2(max(0, width - line_falloff), width);
+}
void main() {
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
- // pass through unchanged
- gl_PointSize = size + pixel_fudge; // 0.5 pixel_fudge on either side
+ /* Align to pixel grid if the viewport size is known. */
+ if (ViewportSize.x > 0) {
+ vec2 scale = ViewportSize * 0.5;
+ vec2 px_pos = (gl_Position.xy + 1) * scale;
+ vec2 adj_pos = round(px_pos - 0.5) + 0.5;
+ gl_Position.xy = adj_pos / scale - 1;
+ }
+
+ /* Pass through parameters. */
finalColor = color;
finalOutlineColor = outlineColor;
+ finalFlags = flags;
+
+ if (!test(0xF)) {
+ finalFlags |= 1;
+ }
+
+ /* Size-dependent line thickness. */
+ float half_width = (0.06 + (size - 10) * 0.04);
+ float line_width = half_width + line_falloff;
+
+ /* Outline thresholds. */
+ thresholds.xy = line_thresholds(line_width);
+
+ /* Inner dot thresholds. */
+ thresholds.zw = line_thresholds(line_width * 1.6);
+
+ /* Extend the primitive size by half line width on either side; odd for symmetry. */
+ float ext_radius = round(0.5 * size) + thresholds.x;
+
+ gl_PointSize = ceil(ext_radius + thresholds.y) * 2 + 1;
+
+ /* Diamond radius. */
+ radii[0] = ext_radius * diagonal_scale;
+
+ /* Circle radius. */
+ radii[1] = ext_radius * circle_scale;
- // calculate concentric radii in pixels
- float radius = 0.5 * gl_PointSize;
+ /* Square radius. */
+ radii[2] = round(ext_radius * square_scale);
- // start at the outside and progress toward the center
- radii[0] = radius;
- radii[1] = radius - pixel_fudge;
- radii[2] = radius - outline_width;
- radii[3] = radius - outline_width - pixel_fudge;
+ /* Min/max cutout offset. */
+ radii[3] = -line_falloff;
- // convert to PointCoord units
- radii /= size;
+ /* Convert to PointCoord units. */
+ radii /= gl_PointSize;
+ thresholds /= gl_PointSize;
}
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index d6991041ec6..7d4ac170489 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -724,7 +724,11 @@ typedef enum eSAction_Flag {
/* don't perform realtime updates */
SACTION_NOREALTIMEUPDATES = (1 << 10),
/* move markers as well as keyframes */
- SACTION_MARKERS_MOVE = (1 << 11)
+ SACTION_MARKERS_MOVE = (1 << 11),
+ /* show interpolation type */
+ SACTION_SHOW_INTERPOLATION = (1 << 12),
+ /* show extremes */
+ SACTION_SHOW_EXTREMES = (1 << 13),
} eSAction_Flag;
/* SpaceAction Mode Settings */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 3fd6fff932b..d03cd1517c0 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -286,10 +286,11 @@ typedef struct ThemeSpace {
char handle_free[4], handle_auto[4], handle_vect[4], handle_align[4], handle_auto_clamped[4];
char handle_sel_free[4], handle_sel_auto[4], handle_sel_vect[4], handle_sel_align[4], handle_sel_auto_clamped[4];
- char ds_channel[4], ds_subchannel[4]; /* dopesheet */
+ char ds_channel[4], ds_subchannel[4], ds_ipoline[4]; /* dopesheet */
char keytype_keyframe[4], keytype_extreme[4], keytype_breakdown[4], keytype_jitter[4], keytype_movehold[4]; /* keytypes */
char keytype_keyframe_select[4], keytype_extreme_select[4], keytype_breakdown_select[4], keytype_jitter_select[4], keytype_movehold_select[4]; /* keytypes */
char keyborder[4], keyborder_select[4];
+ char pad[4];
char console_output[4], console_input[4], console_info[4], console_error[4];
char console_cursor[4], console_select[4];
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index f576ad4866c..e9671754288 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -57,11 +57,11 @@ static const EnumPropertyItem beztriple_handle_type_items[] = {
#endif
const EnumPropertyItem rna_enum_keyframe_handle_type_items[] = {
- {HD_FREE, "FREE", 0, "Free", ""},
- {HD_VECT, "VECTOR", 0, "Vector", ""},
- {HD_ALIGN, "ALIGNED", 0, "Aligned", ""},
- {HD_AUTO, "AUTO", 0, "Automatic", ""},
- {HD_AUTO_ANIM, "AUTO_CLAMPED", 0, "Auto Clamped", "Auto handles clamped to not overshoot"},
+ {HD_FREE, "FREE", ICON_HANDLETYPE_FREE_VEC, "Free", "Completely independent manually set handle"},
+ {HD_ALIGN, "ALIGNED", ICON_HANDLETYPE_ALIGNED_VEC, "Aligned", "Manually set handle with rotation locked together with its pair"},
+ {HD_VECT, "VECTOR", ICON_HANDLETYPE_VECTOR_VEC, "Vector", "Automatic handles that create straight lines"},
+ {HD_AUTO, "AUTO", ICON_HANDLETYPE_AUTO_VEC, "Automatic", "Automatic handles that create smooth curves"},
+ {HD_AUTO_ANIM, "AUTO_CLAMPED", ICON_HANDLETYPE_AUTO_CLAMP_VEC, "Auto Clamped", "Automatic handles that create smooth curves which only change direction at keyframes"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 9c1ced01bd1..56385ee5447 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -3960,6 +3960,18 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
"(pose bones only currently)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
+ prop = RNA_def_property(srna, "show_interpolation", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SACTION_SHOW_INTERPOLATION);
+ RNA_def_property_ui_text(prop, "Show Handles And Interpolation",
+ "Display keyframe handle types and non-bezier interpolation modes");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
+
+ prop = RNA_def_property(srna, "show_extremes", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SACTION_SHOW_EXTREMES);
+ RNA_def_property_ui_text(prop, "Show Curve Extremes",
+ "Mark keyframes where the key value flow changes direction, based on comparison with adjacent keys");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
+
/* editing */
prop = RNA_def_property(srna, "use_auto_merge_keyframes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SACTION_NOTRANSKEYCULL);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 1acba55549a..bbad0ebf26b 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -2849,6 +2849,12 @@ static void rna_def_userdef_theme_space_action(BlenderRNA *brna)
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Preview Range", "Color of preview range overlay");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "interpolation_line", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "ds_ipoline");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Interpolation Line", "Color of lines showing non-bezier interpolation modes");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
}
static void rna_def_userdef_theme_space_nla(BlenderRNA *brna)