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:
-rw-r--r--release/datafiles/userdef/userdef_default_theme.c1
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py2
-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
26 files changed, 569 insertions, 162 deletions
diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c
index daf4b1eb1bc..99744022813 100644
--- a/release/datafiles/userdef/userdef_default_theme.c
+++ b/release/datafiles/userdef/userdef_default_theme.c
@@ -512,6 +512,7 @@ const bTheme U_theme_default = {
.cframe = RGBA(0x5680c2ff),
.ds_channel = RGBA(0x547ca624),
.ds_subchannel = RGBA(0x748da624),
+ .ds_ipoline = RGBA(0x94e575cc),
.keytype_keyframe = RGBA(0xe8e8e8ff),
.keytype_extreme = RGBA(0xe8b3ccff),
.keytype_breakdown = RGBA(0xb3dbe8ff),
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 145eea66d0a..fb8a59097d6 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -335,6 +335,8 @@ class DOPESHEET_MT_view(Menu):
layout.prop(st, "show_frame_indicator")
layout.prop(st, "show_sliders")
layout.prop(st, "show_group_colors")
+ layout.prop(st, "show_interpolation")
+ layout.prop(st, "show_extremes")
layout.prop(st, "use_auto_merge_keyframes")
layout.prop(st, "use_marker_sync")
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)