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:
Diffstat (limited to 'source/blender/editors/animation')
-rw-r--r--source/blender/editors/animation/CMakeLists.txt1
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c191
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c172
-rw-r--r--source/blender/editors/animation/anim_deps.c36
-rw-r--r--source/blender/editors/animation/anim_draw.c163
-rw-r--r--source/blender/editors/animation/anim_filter.c158
-rw-r--r--source/blender/editors/animation/anim_intern.h1
-rw-r--r--source/blender/editors/animation/anim_markers.c303
-rw-r--r--source/blender/editors/animation/anim_ops.c142
-rw-r--r--source/blender/editors/animation/drivers.c148
-rw-r--r--source/blender/editors/animation/keyframes_draw.c960
-rw-r--r--source/blender/editors/animation/keyframes_edit.c10
-rw-r--r--source/blender/editors/animation/keyframes_general.c20
-rw-r--r--source/blender/editors/animation/keyframing.c228
-rw-r--r--source/blender/editors/animation/keyingsets.c18
15 files changed, 1548 insertions, 1003 deletions
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt
index 1bf1bb2a474..13432e38669 100644
--- a/source/blender/editors/animation/CMakeLists.txt
+++ b/source/blender/editors/animation/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../gpu
../../makesdna
../../makesrna
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 8c306ab0159..8896de75472 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -64,11 +64,17 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
+#include "BKE_gpencil.h"
#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_nla.h"
#include "BKE_context.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
+#include "DEG_depsgraph.h"
+
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "UI_resources.h"
@@ -77,7 +83,6 @@
#include "ED_keyframing.h"
#include "BIF_gl.h"
-#include "BIF_glutil.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -120,11 +125,10 @@ static void acf_generic_root_backdrop(bAnimContext *ac, bAnimListElem *ale, floa
/* set backdrop drawing color */
acf->get_backdrop_color(ac, ale, color);
- glColor3fv(color);
/* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
UI_draw_roundbox_corner_set((expanded) ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
- UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8);
+ UI_draw_roundbox_3fvAlpha(true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f);
}
@@ -143,12 +147,18 @@ static void acf_generic_dataexpand_backdrop(bAnimContext *ac, bAnimListElem *ale
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
float color[3];
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
/* set backdrop drawing color */
acf->get_backdrop_color(ac, ale, color);
- glColor3fv(color);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fv(color);
/* no rounded corner - just rectangular box */
- glRectf(offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc);
+ immRectf(pos, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc);
+
+ immUnbindProgram();
}
/* helper method to test if group colors should be drawn */
@@ -213,8 +223,8 @@ static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, floa
}
else {
// FIXME: what happens when the indention is 1 greater than what it should be (due to grouping)?
- int colOfs = 20 - 20 * indent;
- UI_GetThemeColorShade3fv(TH_HEADER, colOfs, r_color);
+ int colOfs = 10 - 10 * indent;
+ UI_GetThemeColorShade3fv(TH_SHADE2, colOfs, r_color);
}
}
@@ -226,12 +236,18 @@ static void acf_generic_channel_backdrop(bAnimContext *ac, bAnimListElem *ale, f
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
float color[3];
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
/* set backdrop drawing color */
acf->get_backdrop_color(ac, ale, color);
- glColor3fv(color);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fv(color);
/* no rounded corners - just rectangular box */
- glRectf(offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc);
+ immRectf(pos, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc);
+
+ immUnbindProgram();
}
/* Indention + Offset ------------------------------------------- */
@@ -422,14 +438,13 @@ static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float ymi
/* set backdrop drawing color */
acf->get_backdrop_color(ac, ale, color);
- glColor3fv(color);
/* rounded corners on LHS only
* - top and bottom
* - special hack: make the top a bit higher, since we are first...
*/
UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
- UI_draw_roundbox_gl_mode(GL_POLYGON, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8);
+ UI_draw_roundbox_3fvAlpha(true, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f);
}
/* name for summary entries */
@@ -624,7 +639,7 @@ static int acf_object_icon(bAnimListElem *ale)
/* icon depends on object-type */
switch (ob->type) {
case OB_LAMP:
- return ICON_OUTLINER_OB_LAMP;
+ return ICON_OUTLINER_OB_LIGHT;
case OB_MESH:
return ICON_OUTLINER_OB_MESH;
case OB_CAMERA:
@@ -637,6 +652,8 @@ static int acf_object_icon(bAnimListElem *ale)
return ICON_OUTLINER_OB_LATTICE;
case OB_SPEAKER:
return ICON_OUTLINER_OB_SPEAKER;
+ case OB_LIGHTPROBE:
+ return ICON_OUTLINER_OB_LIGHTPROBE;
case OB_ARMATURE:
return ICON_OUTLINER_OB_ARMATURE;
case OB_FONT:
@@ -645,6 +662,8 @@ static int acf_object_icon(bAnimListElem *ale)
return ICON_OUTLINER_OB_SURFACE;
case OB_EMPTY:
return ICON_OUTLINER_OB_EMPTY;
+ case OB_GPENCIL:
+ return ICON_OUTLINER_OB_GREASEPENCIL;
default:
return ICON_OBJECT_DATA;
}
@@ -798,9 +817,9 @@ static void acf_group_color(bAnimContext *ac, bAnimListElem *ale, float r_color[
else {
/* highlight only for active */
if (ale->flag & AGRP_ACTIVE)
- UI_GetThemeColorShade3fv(TH_GROUP_ACTIVE, 10, r_color);
+ UI_GetThemeColor3fv(TH_GROUP_ACTIVE, r_color);
else
- UI_GetThemeColorShade3fv(TH_GROUP, 20, r_color);
+ UI_GetThemeColor3fv(TH_GROUP, r_color);
}
}
@@ -815,11 +834,10 @@ static void acf_group_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc
/* set backdrop drawing color */
acf->get_backdrop_color(ac, ale, color);
- glColor3fv(color);
/* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
- UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8);
+ UI_draw_roundbox_3fvAlpha(true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f);
}
/* name for group entries */
@@ -1072,11 +1090,10 @@ static void acf_nla_controls_backdrop(bAnimContext *ac, bAnimListElem *ale, floa
/* set backdrop drawing color */
acf->get_backdrop_color(ac, ale, color);
- glColor3fv(color);
/* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
- UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5);
+ UI_draw_roundbox_3fvAlpha(true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5, color, 1.0f);
}
/* name for nla controls expander entries */
@@ -1438,16 +1455,16 @@ static bAnimChannelType ACF_DSMAT =
acf_dsmat_setting_ptr /* pointer for setting */
};
-/* Lamp Expander ------------------------------------------- */
+/* Light Expander ------------------------------------------- */
// TODO: just get this from RNA?
-static int acf_dslam_icon(bAnimListElem *UNUSED(ale))
+static int acf_dslight_icon(bAnimListElem *UNUSED(ale))
{
- return ICON_LAMP_DATA;
+ return ICON_LIGHT_DATA;
}
/* get the appropriate flag(s) for the setting when it is valid */
-static int acf_dslam_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg)
+static int acf_dslight_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg)
{
/* clear extra return data first */
*neg = false;
@@ -1472,7 +1489,7 @@ static int acf_dslam_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Setting
}
/* get pointer to the setting */
-static void *acf_dslam_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type)
+static void *acf_dslight_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type)
{
Lamp *la = (Lamp *)ale->data;
@@ -1496,9 +1513,9 @@ static void *acf_dslam_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings set
}
/* lamp expander type define */
-static bAnimChannelType ACF_DSLAM =
+static bAnimChannelType ACF_DSLIGHT =
{
- "Lamp Expander", /* type name */
+ "Light Expander", /* type name */
ACHANNEL_ROLE_EXPANDER, /* role */
acf_generic_dataexpand_color, /* backdrop color */
@@ -1507,12 +1524,12 @@ static bAnimChannelType ACF_DSLAM =
acf_generic_basic_offset, /* offset */
acf_generic_idblock_name, /* name */
- acf_generic_idblock_name_prop, /* name prop */
- acf_dslam_icon, /* icon */
+ acf_generic_idblock_name_prop, /* name prop */
+ acf_dslight_icon, /* icon */
acf_generic_dataexpand_setting_valid, /* has setting */
- acf_dslam_setting_flag, /* flag for setting */
- acf_dslam_setting_ptr /* pointer for setting */
+ acf_dslight_setting_flag, /* flag for setting */
+ acf_dslight_setting_ptr /* pointer for setting */
};
/* Texture Expander ------------------------------------------- */
@@ -2019,7 +2036,7 @@ static int acf_dspart_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settin
switch (setting) {
case ACHANNEL_SETTING_EXPAND: /* expanded */
- return PART_DS_EXPAND;
+ return 0;
case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
return ADT_NLA_EVAL_OFF;
@@ -2037,22 +2054,18 @@ static int acf_dspart_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settin
}
/* get pointer to the setting */
-static void *acf_dspart_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type)
+static void *acf_dspart_setting_ptr(bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting, short *type)
{
- ParticleSettings *part = (ParticleSettings *)ale->data;
-
/* clear extra return data first */
*type = 0;
switch (setting) {
case ACHANNEL_SETTING_EXPAND: /* expanded */
- return GET_ACF_FLAG_PTR(part->flag, type);
+ return NULL;
case ACHANNEL_SETTING_SELECT: /* selected */
case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */
case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
- if (part->adt)
- return GET_ACF_FLAG_PTR(part->adt->flag, type);
return NULL;
default: /* unsupported */
@@ -3421,14 +3434,10 @@ static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float y
*/
nla_action_get_color(adt, (bAction *)ale->data, color);
- if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
- /* Yes, the color vector has 4 components, BUT we only want to be using 3 of them! */
- glColor3fv(color);
- }
- else {
- float alpha = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f;
- glColor4f(color[0], color[1], color[2], alpha);
- }
+ if (adt && (adt->flag & ADT_NLA_EDIT_ON))
+ color[3] = 1.0f;
+ else
+ color[3] = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f;
/* only on top left corner, to show that this channel sits on top of the preceding ones
* while still linking into the action line strip to the right
@@ -3438,7 +3447,7 @@ static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float y
/* draw slightly shifted up vertically to look like it has more separation from other channels,
* but we then need to slightly shorten it so that it doesn't look like it overlaps
*/
- UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8);
+ UI_draw_roundbox_4fv(true, offset, yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8, color);
}
/* name for nla action entries */
@@ -3574,7 +3583,7 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_FILLDRIVERS; /* Drivers Expander */
animchannelTypeInfo[type++] = &ACF_DSMAT; /* Material Channel */
- animchannelTypeInfo[type++] = &ACF_DSLAM; /* Lamp Channel */
+ animchannelTypeInfo[type++] = &ACF_DSLIGHT; /* Light Channel */
animchannelTypeInfo[type++] = &ACF_DSCAM; /* Camera Channel */
animchannelTypeInfo[type++] = &ACF_DSCACHEFILE; /* CacheFile Channel */
animchannelTypeInfo[type++] = &ACF_DSCUR; /* Curve Channel */
@@ -3827,8 +3836,8 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
selected = 0;
/* set blending again, as may not be set in previous step */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
/* step 1) draw backdrop ........................................... */
if (acf->draw_backdrop)
@@ -3847,7 +3856,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
}
/* turn off blending, since not needed anymore... */
- glDisable(GL_BLEND);
+ GPU_blend(false);
/* step 4) draw special toggles .................................
* - in Graph Editor, checkboxes for visibility in curves area
@@ -3862,15 +3871,20 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
/* for F-Curves, draw color-preview of curve behind checkbox */
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
FCurve *fcu = (FCurve *)ale->data;
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* F-Curve channels need to have a special 'color code' box drawn, which is colored with whatever
* color the curve has stored
*/
- glColor3fv(fcu->color);
+ immUniformColor3fv(fcu->color);
/* just a solid color rect
*/
- glRectf(offset, yminc, offset + ICON_WIDTH, ymaxc);
+ immRectf(pos, offset, yminc, offset + ICON_WIDTH, ymaxc);
+
+ immUnbindProgram();
}
/* icon is drawn as widget now... */
if (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
@@ -3895,27 +3909,39 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
if (acf->name && !achannel_is_being_renamed(ac, acf, channel_index)) {
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */
+ unsigned char col[4];
/* set text color */
/* XXX: if active, highlight differently? */
+
if (selected)
- UI_ThemeColor(TH_TEXT_HI);
+ UI_GetThemeColor4ubv(TH_TEXT_HI, col);
else
- UI_ThemeColor(TH_TEXT);
+ UI_GetThemeColor4ubv(TH_TEXT, col);
/* get name */
acf->name(ale, name);
offset += 3;
- UI_fontstyle_draw_simple(fstyle, offset, ytext, name);
+ UI_fontstyle_draw_simple(fstyle, offset, ytext, name, col);
/* draw red underline if channel is disabled */
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE) && (ale->flag & FCURVE_DISABLED)) {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* FIXME: replace hardcoded color here, and check on extents! */
- glColor3f(1.0f, 0.0f, 0.0f);
- glLineWidth(2.0);
- fdrawline((float)(offset), yminc,
- (float)(v2d->cur.xmax), yminc);
+ immUniformColor3f(1.0f, 0.0f, 0.0f);
+
+ GPU_line_width(2.0f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, (float)offset, yminc);
+ immVertex2f(pos, (float)v2d->cur.xmax, yminc);
+ immEnd();
+
+ immUnbindProgram();
}
}
@@ -3929,10 +3955,13 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
short draw_sliders = 0;
float ymin_ofs = 0.0f;
float color[3];
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* get and set backdrop color */
acf->get_backdrop_color(ac, ale, color);
- glColor3fv(color);
+ immUniformColor3fv(color);
/* check if we need to show the sliders */
if ((ac->sl) && ELEM(ac->spacetype, SPACE_ACTION, SPACE_IPO)) {
@@ -3990,7 +4019,9 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
* - starts from the point where the first toggle/slider starts,
* - ends past the space that might be reserved for a scroller
*/
- glRectf(v2d->cur.xmax - (float)offset, yminc + ymin_ofs, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc);
+ immRectf(pos, v2d->cur.xmax - (float)offset, yminc + ymin_ofs, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc);
+
+ immUnbindProgram();
}
}
@@ -4020,8 +4051,25 @@ static void achannel_setting_flush_widget_cb(bContext *C, void *ale_npoin, void
return;
}
- if (ale_setting->type == ANIMTYPE_GPLAYER)
+ if (ale_setting->type == ANIMTYPE_GPLAYER) {
+ /* draw cache updates for settings that affect the visible strokes */
+ if (setting == ACHANNEL_SETTING_VISIBLE) {
+ bGPdata *gpd = (bGPdata *)ale_setting->id;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ }
+
+ /* UI updates */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ }
+
+ /* tag copy-on-write flushing (so that the settings will have an effect) */
+ if (ale_setting->id) {
+ DEG_id_tag_update(ale_setting->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ if (ale_setting->adt && ale_setting->adt->action) {
+ /* action is it's own datablock, so has to be tagged specifically... */
+ DEG_id_tag_update(&ale_setting->adt->action->id, DEG_TAG_COPY_ON_WRITE);
+ }
/* verify animation context */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -4073,6 +4121,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
AnimData *adt = BKE_animdata_from_id(id);
FCurve *fcu = (FCurve *)fcu_poin;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ReportList *reports = CTX_wm_reports(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
@@ -4098,7 +4147,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
flag |= INSERTKEY_REPLACE;
/* insert a keyframe for this F-Curve */
- done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
+ done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
if (done)
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -4113,6 +4162,7 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
KeyBlock *kb = (KeyBlock *)kb_poin;
char *rna_path = BKE_keyblock_curval_rnapath_get(key, kb);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ReportList *reports = CTX_wm_reports(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
@@ -4136,14 +4186,14 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
/* find or create new F-Curve */
// XXX is the group name for this ok?
bAction *act = verify_adt_action(bmain, (ID *)key, 1);
- FCurve *fcu = verify_fcurve(act, NULL, &ptr, rna_path, 0, 1);
+ FCurve *fcu = verify_fcurve(bmain, act, NULL, &ptr, rna_path, 0, 1);
/* set the special 'replace' flag if on a keyframe */
if (fcurve_frame_has_keyframe(fcu, cfra, 0))
flag |= INSERTKEY_REPLACE;
/* insert a keyframe for this F-Curve */
- done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
+ done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
if (done)
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -4164,6 +4214,7 @@ static void achannel_setting_slider_nla_curve_cb(bContext *C, void *UNUSED(id_po
PropertyRNA *prop;
int index;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ReportList *reports = CTX_wm_reports(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
@@ -4186,7 +4237,7 @@ static void achannel_setting_slider_nla_curve_cb(bContext *C, void *UNUSED(id_po
flag |= INSERTKEY_REPLACE;
/* insert a keyframe for this F-Curve */
- done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
+ done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
if (done)
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -4204,11 +4255,12 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAni
void *ptr;
const char *tooltip;
uiBut *but = NULL;
+ bool enabled;
/* get the flag and the pointer to that flag */
flag = acf->setting_flag(ac, setting, &negflag);
ptr = acf->setting_ptr(ale, setting, &ptrsize);
- /* enabled = ANIM_channel_setting_get(ac, ale, setting); */ /* UNUSED */
+ enabled = ANIM_channel_setting_get(ac, ale, setting);
/* get the base icon for the setting */
switch (setting) {
@@ -4230,8 +4282,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAni
break;
case ACHANNEL_SETTING_MOD_OFF: /* modifiers disabled */
- icon = ICON_MODIFIER;
- usetoggle = false;
+ icon = ICON_MODIFIER_OFF;
tooltip = TIP_("F-Curve modifiers are disabled");
break;
@@ -4261,8 +4312,8 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAni
break;
case ACHANNEL_SETTING_MUTE: /* muted speaker */
- //icon = ((enabled) ? ICON_MUTE_IPO_ON : ICON_MUTE_IPO_OFF);
- icon = ICON_MUTE_IPO_OFF;
+ icon = ((enabled) ? ICON_CHECKBOX_DEHLT : ICON_CHECKBOX_HLT);
+ usetoggle = false;
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
tooltip = TIP_("Does F-Curve contribute to result");
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index c125c129e1d..2dec9c251f5 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -50,13 +50,15 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_gpencil.h"
#include "BKE_context.h"
+#include "BKE_library.h"
#include "BKE_mask.h"
#include "BKE_global.h"
-#include "BKE_library.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph_build.h"
#include "UI_view2d.h"
@@ -65,6 +67,7 @@
#include "ED_keyframes_edit.h" // XXX move the select modes out of there!
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -1725,8 +1728,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
bGPDlayer *gpl = (bGPDlayer *)ale->data;
/* try to delete the layer's data and the layer itself */
- BKE_gpencil_free_frames(gpl);
- BLI_freelinkN(&gpd->layers, gpl);
+ BKE_gpencil_layer_delete(gpd, gpl);
break;
}
case ANIMTYPE_MASKLAYER:
@@ -1747,7 +1749,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_relations_tag_update(CTX_data_main(C));
return OPERATOR_FINISHED;
}
@@ -2298,18 +2300,9 @@ static int animchannels_find_exec(bContext *C, wmOperator *op)
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
- /* update filter text, and ensure that filter is enabled if there's something there
- * NOTE: we turn the filter off if there's nothing (this is a quick shortcut for dismissing)
- */
+ /* update filter text */
RNA_string_get(op->ptr, "query", ac.ads->searchstr);
- if (ac.ads->searchstr[0]) {
- ac.ads->filterflag |= ADS_FILTER_BY_FCU_NAME;
- }
- else {
- ac.ads->filterflag &= ~ADS_FILTER_BY_FCU_NAME;
- }
-
/* redraw */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -2346,10 +2339,24 @@ static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* 'standard' behavior - check if selected, then apply relevant selection */
- if (RNA_boolean_get(op->ptr, "invert"))
- ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_INVERT);
- else
- ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_ADD);
+ const int action = RNA_enum_get(op->ptr, "action");
+ switch (action) {
+ case SEL_TOGGLE:
+ ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_ADD);
+ break;
+ case SEL_SELECT:
+ ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_ADD);
+ break;
+ case SEL_DESELECT:
+ ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_CLEAR);
+ break;
+ case SEL_INVERT:
+ ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_INVERT);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
@@ -2357,11 +2364,11 @@ static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void ANIM_OT_channels_select_all_toggle(wmOperatorType *ot)
+static void ANIM_OT_channels_select_all(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select All";
- ot->idname = "ANIM_OT_channels_select_all_toggle";
+ ot->idname = "ANIM_OT_channels_select_all";
ot->description = "Toggle selection of all animation channels";
/* api callbacks */
@@ -2371,13 +2378,13 @@ static void ANIM_OT_channels_select_all_toggle(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "");
+ /* properties */
+ WM_operator_properties_select_all(ot);
}
-/* ******************** Borderselect Operator *********************** */
+/* ******************** Box Select Operator *********************** */
-static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selectmode)
+static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectmode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -2406,7 +2413,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- /* loop over data, doing border select */
+ /* loop over data, doing box select */
for (ale = anim_data.first; ale; ale = ale->next) {
if (ac->datatype == ANIMCONT_NLA)
ymin = ymax - NLACHANNEL_STEP(snla);
@@ -2451,7 +2458,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec
/* ------------------- */
-static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
+static int animchannels_box_select_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
rcti rect;
@@ -2477,8 +2484,8 @@ static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
selectmode = ACHANNEL_SETFLAG_CLEAR;
}
- /* apply borderselect animation channels */
- borderselect_anim_channels(&ac, &rect, selectmode);
+ /* apply box_select animation channels */
+ box_select_anim_channels(&ac, &rect, selectmode);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
@@ -2486,18 +2493,18 @@ static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void ANIM_OT_channels_select_border(wmOperatorType *ot)
+static void ANIM_OT_channels_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->idname = "ANIM_OT_channels_select_border";
+ ot->name = "Box Select";
+ ot->idname = "ANIM_OT_channels_select_box";
ot->description = "Select all animation channels within the specified region";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = animchannels_borderselect_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = animchannels_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = animedit_poll_channels_nla_tweakmode_off;
@@ -2505,7 +2512,7 @@ static void ANIM_OT_channels_select_border(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* rna */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
}
/* ******************* Rename Operator ***************************** */
@@ -2681,18 +2688,21 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
}
case ANIMTYPE_OBJECT:
{
+#if 0
bDopeSheet *ads = (bDopeSheet *)ac->data;
Scene *sce = (Scene *)ads->source;
+#endif
+ ViewLayer *view_layer = ac->view_layer;
Base *base = (Base *)ale->data;
Object *ob = base->object;
AnimData *adt = ob->adt;
/* set selection status */
- if ((ob->restrictflag & OB_RESTRICT_SELECT) == 0) {
+ if (base->flag & BASE_SELECTABLE) {
if (selectmode == SELECT_INVERT) {
/* swap select */
- base->flag ^= SELECT;
- ob->flag = base->flag;
+ ED_object_base_select(base, BA_INVERT);
+ BKE_scene_object_base_flag_sync_from_base(base);
if (adt) adt->flag ^= ADT_UI_SELECTED;
}
@@ -2701,26 +2711,26 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
/* deselect all */
/* TODO: should this deselect all other types of channels too? */
- for (b = sce->base.first; b; b = b->next) {
- b->flag &= ~SELECT;
- b->object->flag = b->flag;
+ for (b = view_layer->object_bases.first; b; b = b->next) {
+ ED_object_base_select(b, BA_DESELECT);
+ BKE_scene_object_base_flag_sync_from_base(b);
if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED | ADT_UI_ACTIVE);
}
/* select object now */
- base->flag |= SELECT;
- ob->flag |= SELECT;
+ ED_object_base_select(base, BA_SELECT);
+ BKE_scene_object_base_flag_sync_from_base(base);
if (adt) adt->flag |= ADT_UI_SELECTED;
}
/* change active object - regardless of whether it is now selected [T37883] */
- ED_base_object_activate(C, base); /* adds notifier */
+ ED_object_base_activate(C, base); /* adds notifier */
if ((adt) && (adt->flag & ADT_UI_SELECTED))
adt->flag |= ADT_UI_ACTIVE;
/* ensure we exit editmode on whatever object was active before to avoid getting stuck there - T48747 */
- if (ob != sce->obedit) {
+ if (ob != CTX_data_edit_object(C)) {
ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
}
@@ -2909,6 +2919,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
}
case ANIMTYPE_GPLAYER:
{
+ bGPdata *gpd = (bGPdata *)ale->id;
bGPDlayer *gpl = (bGPDlayer *)ale->data;
/* select/deselect */
@@ -2925,10 +2936,12 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
/* change active layer, if this is selected (since we must always have an active layer) */
if (gpl->flag & GP_LAYER_SELECT) {
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER);
+ /* update other layer status */
+ BKE_gpencil_layer_setactive(gpd, gpl);
}
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); /* Grease Pencil updates */
- notifierFlags |= (ND_ANIMCHAN | NA_EDITED); /* Animation Ediotrs updates */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); /* Grease Pencil updates */
+ notifierFlags |= (ND_ANIMCHAN | NA_EDITED); /* Animation Editors updates */
break;
}
case ANIMTYPE_MASKDATABLOCK:
@@ -3150,8 +3163,8 @@ static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
void ED_operatortypes_animchannels(void)
{
- WM_operatortype_append(ANIM_OT_channels_select_all_toggle);
- WM_operatortype_append(ANIM_OT_channels_select_border);
+ WM_operatortype_append(ANIM_OT_channels_select_all);
+ WM_operatortype_append(ANIM_OT_channels_select_box);
WM_operatortype_append(ANIM_OT_channels_click);
WM_operatortype_append(ANIM_OT_channel_select_keys);
@@ -3184,62 +3197,7 @@ void ED_operatortypes_animchannels(void)
// TODO: check on a poll callback for this, to get hotkeys into menus
void ED_keymap_animchannels(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Animation Channels", 0, 0);
- wmKeyMapItem *kmi;
-
- /* click-select */
- /* XXX for now, only leftmouse.... */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, 0, 0);
- RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", true);
- RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "children_only", true);
-
- /* rename */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
- RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, KM_SHIFT, 0)->ptr, "extend", true);
-
- /* find (i.e. a shortcut for setting the name filter) */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
-
- /* deselect all */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", AKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", true);
-
- /* borderselect */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", BKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", EVT_TWEAK_L, KM_ANY, 0, 0);
-
- /* delete */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", DELKEY, KM_PRESS, 0, 0);
-
- /* settings */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_enable", WKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_disable", WKEY, KM_PRESS, KM_ALT, 0);
-
- /* settings - specialized hotkeys */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_editable_toggle", TABKEY, KM_PRESS, 0, 0);
-
- /* expand/collapse */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "all", false);
- kmi = WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "all", false);
-
- /* rearranging */
- RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEUPKEY, KM_PRESS, 0, 0)->ptr, "direction", REARRANGE_ANIMCHAN_UP);
- RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEDOWNKEY, KM_PRESS, 0, 0)->ptr, "direction", REARRANGE_ANIMCHAN_DOWN);
- RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "direction", REARRANGE_ANIMCHAN_TOP);
- RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "direction", REARRANGE_ANIMCHAN_BOTTOM);
-
- /* grouping */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_group", GKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_ungroup", GKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_ensure(keyconf, "Animation Channels", 0, 0);
}
/* ************************************************************************** */
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 6697997b133..c9b393601b2 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -47,13 +47,14 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_gpencil.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_sequencer.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "ED_anim_api.h"
@@ -77,7 +78,16 @@ void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
adt = BKE_animdata_from_id(id);
if (adt) {
adt->recalc |= ADT_RECALC_ANIM;
- DAG_id_tag_update(id, OB_RECALC_TIME);
+ DEG_id_tag_update(id, OB_RECALC_TIME);
+ if (adt->action != NULL) {
+ DEG_id_tag_update(&adt->action->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ }
+
+ /* Tag copy on the main object if updating anything directly inside AnimData */
+ if (ELEM(ale->type, ANIMTYPE_ANIMDATA, ANIMTYPE_NLAACTION, ANIMTYPE_NLATRACK, ANIMTYPE_NLACURVE)) {
+ DEG_id_tag_update(id, DEG_TAG_TIME | DEG_TAG_COPY_ON_WRITE);
+ return;
}
/* update data */
@@ -98,13 +108,13 @@ void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
else {
/* in other case we do standard depsgraph update, ideally
* we'd be calling property update functions here too ... */
- DAG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); // XXX or do we want something more restrictive?
+ DEG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); // XXX or do we want something more restrictive?
}
}
/* tags the given ID block for refreshes (if applicable) due to
* Animation Editor editing */
-void ANIM_id_update(Scene *UNUSED(scene), ID *id)
+void ANIM_id_update(Main *bmain, ID *id)
{
if (id) {
AnimData *adt = BKE_animdata_from_id(id);
@@ -114,7 +124,7 @@ void ANIM_id_update(Scene *UNUSED(scene), ID *id)
adt->recalc |= ADT_RECALC_ANIM;
/* set recalc flags */
- DAG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); // XXX or do we want something more restrictive?
+ DEG_id_tag_update_ex(bmain, id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); // XXX or do we want something more restrictive?
}
}
@@ -404,6 +414,10 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
ale->update &= ~ANIM_UPDATE_DEPS;
ANIM_list_elem_update(ac->bmain, ac->scene, ale);
}
+ /* disable handles to avoid crash */
+ if (ale->update & ANIM_UPDATE_HANDLES) {
+ ale->update &= ~ANIM_UPDATE_HANDLES;
+ }
}
else if (ale->datatype == ALE_FCURVE) {
FCurve *fcu = ale->key_data;
@@ -425,12 +439,22 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
ANIM_list_elem_update(ac->bmain, ac->scene, ale);
}
}
- else if (ale->datatype == ALE_NLASTRIP) {
+ else if (ELEM(ale->type, ANIMTYPE_ANIMDATA, ANIMTYPE_NLAACTION, ANIMTYPE_NLATRACK, ANIMTYPE_NLACURVE)) {
if (ale->update & ANIM_UPDATE_DEPS) {
ale->update &= ~ANIM_UPDATE_DEPS;
ANIM_list_elem_update(ac->bmain, ac->scene, ale);
}
}
+ else if (ale->update) {
+#if 0
+ if (G.debug & G_DEBUG) {
+ printf("%s: Unhandled animchannel updates (%d) for type=%d (%p)\n",
+ __func__, ale->update, ale->type, ale->data);
+ }
+#endif
+ /* Prevent crashes in cases where it can't be handled */
+ ale->update = 0;
+ }
BLI_assert(ale->update == 0);
}
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index a21bc4989b5..239ab5f8206 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -58,55 +58,77 @@
#include "RNA_access.h"
-#include "BIF_gl.h"
-
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
/* *************************************************** */
/* CURRENT FRAME DRAWING */
/* Draw current frame number in a little green box beside the current frame indicator */
-static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const bool time)
+void ANIM_draw_cfra_number(const bContext *C, View2D *v2d, short flag)
{
+ Scene *scene = CTX_data_scene(C);
+ const float time = scene->r.cfra + scene->r.subframe;
+ const float cfra = (float)(time * scene->r.framelen);
+ const bool show_time = (flag & DRAWCFRA_UNIT_SECONDS) != 0;
+
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- float xscale, yscale, x, y;
- char numstr[32] = " t"; /* t is the character to start replacing from */
+ unsigned char col[4];
+ float color[4];
+ float xscale, x, y;
+ char numstr[32] = " t "; /* t is the character to start replacing from */
+ float hlen;
int slen;
/* because the frame number text is subject to the same scaling as the contents of the view */
- UI_view2d_scale_get(v2d, &xscale, &yscale);
- glScalef(1.0f / xscale, 1.0f, 1.0f);
+ UI_view2d_scale_get(v2d, &xscale, NULL);
+ GPU_matrix_push();
+ GPU_matrix_scale_2f(1.0f / xscale, 1.0f);
/* get timecode string
* - padding on str-buf passed so that it doesn't sit on the frame indicator
- * - power = 0, gives 'standard' behavior for time
- * but power = 1 is required for frames (to get integer frames)
*/
- if (time) {
- BLI_timecode_string_from_time(&numstr[4], sizeof(numstr) - 4, 0, FRA2TIME(cfra), FPS, U.timecode_style);
+ if (show_time) {
+ BLI_timecode_string_from_time(&numstr[2], sizeof(numstr) - 2, 0, FRA2TIME(cfra), FPS, U.timecode_style);
}
else {
- BLI_timecode_string_from_time_seconds(&numstr[4], sizeof(numstr) - 4, 1, cfra);
+ BLI_timecode_string_from_time_seconds(&numstr[2], sizeof(numstr) - 2, 1, cfra);
}
slen = UI_fontstyle_string_width(fstyle, numstr) - 1;
+ hlen = slen * 0.5f;
/* get starting coordinates for drawing */
x = cfra * xscale;
- y = 0.9f * U.widget_unit;
+ y = -0.1f * U.widget_unit;
/* draw green box around/behind text */
- UI_ThemeColorShade(TH_CFRAME, 0);
- glRectf(x, y, x + slen, y + 0.75f * U.widget_unit);
-
- /* draw current frame number - black text */
- UI_ThemeColor(TH_TEXT);
- UI_fontstyle_draw_simple(fstyle, x - 0.25f * U.widget_unit, y + 0.15f * U.widget_unit, numstr);
+ UI_GetThemeColor4fv(TH_CFRAME, color);
+ color[3] = 3.0f;
+
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_aa(true,
+ x - hlen - 0.1f * U.widget_unit,
+ y + 3.0f,
+ x + hlen + 0.1f * U.widget_unit,
+ y -3.0f + U.widget_unit,
+ 0.1f * U.widget_unit,
+ color);
+
+ /* draw current frame number */
+ UI_GetThemeColor4ubv(TH_TEXT_HI, col);
+ UI_fontstyle_draw_simple(fstyle,
+ x - hlen - 0.15f * U.widget_unit,
+ y + 0.28f * U.widget_unit,
+ numstr, col);
/* restore view transform */
- glScalef(xscale, 1.0, 1.0);
+ GPU_matrix_pop();
}
/* General call for drawing current frame indicator in animation editor */
@@ -114,24 +136,24 @@ void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
{
Scene *scene = CTX_data_scene(C);
- /* Draw a light green line to indicate current frame */
- UI_ThemeColor(TH_CFRAME);
-
const float time = scene->r.cfra + scene->r.subframe;
const float x = (float)(time * scene->r.framelen);
- glLineWidth((flag & DRAWCFRA_WIDE) ? 3.0 : 2.0);
+ GPU_line_width((flag & DRAWCFRA_WIDE) ? 3.0 : 2.0);
- glBegin(GL_LINES);
- glVertex2f(x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */
- glVertex2f(x, v2d->cur.ymax);
- glEnd();
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- /* Draw current frame number in a little box */
- if (flag & DRAWCFRA_SHOW_NUMBOX) {
- UI_view2d_view_orthoSpecial(CTX_wm_region(C), v2d, 1);
- draw_cfra_number(scene, v2d, x, (flag & DRAWCFRA_UNIT_SECONDS) != 0);
- }
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ /* Draw a light green line to indicate current frame */
+ immUniformThemeColor(TH_CFRAME);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */
+ immVertex2f(pos, x, v2d->cur.ymax);
+ immEnd();
+ immUnbindProgram();
}
/* *************************************************** */
@@ -145,24 +167,74 @@ void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width)
/* only draw this if preview range is set */
if (PRVRANGEON) {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShadeAlpha(TH_ANIM_PREVIEW_RANGE, -25, -30);
+ //immUniformColor4f(0.8f, 0.44f, 0.1f, 0.2f); /* XXX: Fix this hardcoded color (anim_active) */
/* only draw two separate 'curtains' if there's no overlap between them */
if (PSFRA < PEFRA + end_frame_width) {
- glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
- glRectf((float)(PEFRA + end_frame_width), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
+ immRectf(pos, (float)(PEFRA + end_frame_width), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
}
else {
- glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
}
- glDisable(GL_BLEND);
+ immUnbindProgram();
+
+ GPU_blend(false);
}
}
/* *************************************************** */
+/* SCENE FRAME RANGE */
+
+/* Draw frame range guides (for scene frame range) in background */
+// TODO: Should we still show these when preview range is enabled?
+void ANIM_draw_framerange(Scene *scene, View2D *v2d)
+{
+ /* draw darkened area outside of active timeline frame range */
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShadeAlpha(TH_BACK, -25, -100);
+
+ if (SFRA < EFRA) {
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax);
+ immRectf(pos, (float)EFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ }
+ else {
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ }
+
+ GPU_blend(false);
+
+ /* thin lines where the actual frames are */
+ immUniformThemeColorShade(TH_BACK, -60);
+
+ immBegin(GPU_PRIM_LINES, 4);
+
+ immVertex2f(pos, (float)SFRA, v2d->cur.ymin);
+ immVertex2f(pos, (float)SFRA, v2d->cur.ymax);
+
+ immVertex2f(pos, (float)EFRA, v2d->cur.ymin);
+ immVertex2f(pos, (float)EFRA, v2d->cur.ymax);
+
+ immEnd();
+ immUnbindProgram();
+}
+
+/* *************************************************** */
/* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes) */
/* Obtain the AnimData block providing NLA-mapping for the given channel (if applicable) */
@@ -479,12 +551,12 @@ static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prev
}
/* populate tree with keyframe nodes */
- scene_to_keylist(&ads, scene, &keys, NULL);
- gpencil_to_keylist(&ads, scene->gpd, &keys);
+ scene_to_keylist(&ads, scene, &keys, 0);
+ gpencil_to_keylist(&ads, scene->gpd, &keys, false);
if (ob) {
- ob_to_keylist(&ads, ob, &keys, NULL);
- gpencil_to_keylist(&ads, ob->gpd, &keys);
+ ob_to_keylist(&ads, ob, &keys, 0);
+ gpencil_to_keylist(&ads, ob->data, &keys, false);
}
if (mask) {
@@ -492,9 +564,6 @@ static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prev
mask_to_keylist(&ads, masklay, &keys);
}
- /* build linked-list for searching */
- BLI_dlrbTree_linkedlist_sync(&keys);
-
/* find matching keyframe in the right direction */
do {
aknext = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfranext);
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index fdfe08e03b6..5f23762386e 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -72,8 +72,10 @@
#include "DNA_speaker_types.h"
#include "DNA_world_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_layer_types.h"
#include "MEM_guardedalloc.h"
@@ -83,13 +85,14 @@
#include "BLI_ghash.h"
#include "BLI_string.h"
-#include "BKE_animsys.h"
#include "BKE_action.h"
-#include "BKE_fcurve.h"
+#include "BKE_animsys.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
-#include "BKE_group.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
@@ -130,11 +133,11 @@ static void animedit_get_yscale_factor(bAnimContext *ac)
/* Note: there's a similar function in key.c (BKE_key_from_object) */
static Key *actedit_get_shapekeys(bAnimContext *ac)
{
- Scene *scene = ac->scene;
+ ViewLayer *view_layer = ac->view_layer;
Object *ob;
Key *key;
- ob = OBACT;
+ ob = OBACT(view_layer);
if (ob == NULL)
return NULL;
@@ -228,6 +231,7 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
ac->mode = saction->mode;
return true;
}
+
case SACTCONT_DOPESHEET: /* DopeSheet */
/* update scene-pointer (no need to check for pinning yet, as not implemented) */
saction->ads.source = (ID *)ac->scene;
@@ -238,6 +242,28 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
ac->mode = saction->mode;
return true;
+ case SACTCONT_TIMELINE: /* Timeline */
+ /* update scene-pointer (no need to check for pinning yet, as not implemented) */
+ saction->ads.source = (ID *)ac->scene;
+
+ /* sync scene's "selected keys only" flag with our "only selected" flag
+ * XXX: This is a workaround for T55525. We shouldn't really be syncing the flags like this,
+ * but it's a simpler fix for now than also figuring out how the next/prev keyframe tools
+ * should work in the 3D View if we allowed full access to the timeline's dopesheet filters
+ * (i.e. we'd have to figure out where to host those settings, to be on a scene level like
+ * this flag currently is, along with several other unknowns)
+ */
+ if (ac->scene->flag & SCE_KEYS_NO_SELONLY)
+ saction->ads.filterflag &= ~ADS_FILTER_ONLYSEL;
+ else
+ saction->ads.filterflag |= ADS_FILTER_ONLYSEL;
+
+ ac->datatype = ANIMCONT_TIMELINE;
+ ac->data = &saction->ads;
+
+ ac->mode = saction->mode;
+ return true;
+
default: /* unhandled yet */
ac->datatype = ANIMCONT_NONE;
ac->data = NULL;
@@ -380,8 +406,10 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
ac->scene = scene;
if (scene) {
ac->markers = ED_context_get_markers(C);
- ac->obact = (scene->basact) ? scene->basact->object : NULL;
}
+ ac->depsgraph = CTX_data_depsgraph(C);
+ ac->view_layer = CTX_data_view_layer(C);
+ ac->obact = (ac->view_layer->basact) ? ac->view_layer->basact->object : NULL;
ac->sa = sa;
ac->ar = ar;
ac->sl = sl;
@@ -1194,7 +1222,7 @@ static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, eAnim_Chan
/* only include if this curve is active */
if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) {
/* name based filtering... */
- if ( ((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) && (owner_id) ) {
+ if ( ((ads) && (ads->searchstr[0] != '\0')) && (owner_id) ) {
if (skip_fcurve_with_name(ads, fcu, channel_type, owner, owner_id))
continue;
}
@@ -1426,7 +1454,7 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
/* only include if this track is active */
if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
/* name based filtering... */
- if (((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) && (owner_id)) {
+ if (((ads) && (ads->searchstr[0] != '\0')) && (owner_id)) {
bool track_ok = false, strip_ok = false;
/* check if the name of the track, or the strips it has are ok... */
@@ -1597,8 +1625,8 @@ static size_t animdata_filter_gpencil_layers_data(ListBase *anim_data, bDopeShee
bGPDlayer *gpl;
size_t items = 0;
- /* loop over layers as the conditions are acceptable */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* loop over layers as the conditions are acceptable (top-Down order) */
+ for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) {
/* only if selected */
if (ANIMCHANNEL_SELOK(SEL_GPL(gpl)) ) {
/* only if editable */
@@ -1606,7 +1634,7 @@ static size_t animdata_filter_gpencil_layers_data(ListBase *anim_data, bDopeShee
/* active... */
if (!(filter_mode & ANIMFILTER_ACTIVE) || (gpl->flag & GP_LAYER_ACTIVE)) {
/* skip layer if the name doesn't match the filter string */
- if ((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) {
+ if ((ads) && (ads->searchstr[0] != '\0')) {
if (name_matches_dopesheet_filter(ads, gpl->info) == false)
continue;
}
@@ -1633,7 +1661,7 @@ static size_t animdata_filter_gpencil_data(ListBase *anim_data, bDopeSheet *ads,
*/
if (filter_mode & ANIMFILTER_ANIMDATA) {
/* just add GPD as a channel - this will add everything needed */
- ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
+ ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, gpd);
}
else {
ListBase tmp_data = {NULL, NULL};
@@ -1673,6 +1701,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi
if (ads->filterflag & ADS_FILTER_GP_3DONLY) {
Scene *scene = (Scene *)ads->source;
+ ViewLayer *view_layer = (ViewLayer *)ac->view_layer;
Base *base;
/* Active scene's GPencil block first - No parent item needed... */
@@ -1681,9 +1710,9 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi
}
/* Objects in the scene */
- for (base = scene->base.first; base; base = base->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
/* Only consider this object if it has got some GP data (saving on all the other tests) */
- if (base->object && base->object->gpd) {
+ if (base->object && (base->object->type == OB_GPENCIL)) {
Object *ob = base->object;
/* firstly, check if object can be included, by the following factors:
@@ -1697,14 +1726,14 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi
*/
if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
/* layer visibility - we check both object and base, since these may not be in sync yet */
- if ((scene->lay & (ob->lay | base->lay)) == 0) continue;
+ if ((base->flag & BASE_VISIBLE) == 0) continue;
/* outliner restrict-flag */
if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
}
/* check selection and object type filters */
- if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == scene->basact)*/) ) {
+ if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED) /*|| (base == scene->basact)*/) ) {
/* only selected should be shown */
continue;
}
@@ -1713,14 +1742,14 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi
* objects by the grouped status is on
* - used to ease the process of doing multiple-character choreographies
*/
- if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) {
- if (BKE_group_object_exists(ads->filter_grp, ob) == 0)
+ if (ads->filter_grp != NULL) {
+ if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0)
continue;
}
/* finally, include this object's grease pencil datablock */
/* XXX: Should we store these under expanders per item? */
- items += animdata_filter_gpencil_data(anim_data, ads, ob->gpd, filter_mode);
+ items += animdata_filter_gpencil_data(anim_data, ads, ob->data, filter_mode);
}
}
}
@@ -1944,25 +1973,26 @@ static size_t animdata_filter_ds_nodetree(bAnimContext *ac, ListBase *anim_data,
static size_t animdata_filter_ds_linestyle(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
{
- SceneRenderLayer *srl;
+ ViewLayer *view_layer;
FreestyleLineSet *lineset;
size_t items = 0;
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
if (lineset->linestyle) {
lineset->linestyle->id.tag |= LIB_TAG_DOIT;
}
}
}
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
+ for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
/* skip render layers without Freestyle enabled */
- if (!(srl->layflag & SCE_LAY_FRS))
+ if ((view_layer->flag & VIEW_LAYER_FREESTYLE) == 0) {
continue;
+ }
/* loop over linesets defined in the render layer */
- for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
FreestyleLineStyle *linestyle = lineset->linestyle;
ListBase tmp_data = {NULL, NULL};
size_t tmp_items = 0;
@@ -2047,7 +2077,9 @@ static size_t animdata_filter_ds_texture(bAnimContext *ac, ListBase *anim_data,
return items;
}
-/* NOTE: owner_id is either material, lamp, or world block, which is the direct owner of the texture stack in question */
+/* NOTE: owner_id is the direct owner of the texture stack in question
+ * It used to be Material/Lamp/World before the Blender Internal removal for 2.8
+ */
static size_t animdata_filter_ds_textures(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, int filter_mode)
{
MTex **mtex = NULL;
@@ -2059,24 +2091,6 @@ static size_t animdata_filter_ds_textures(bAnimContext *ac, ListBase *anim_data,
return 0;
switch (GS(owner_id->name)) {
- case ID_MA:
- {
- Material *ma = (Material *)owner_id;
- mtex = (MTex **)(&ma->mtex);
- break;
- }
- case ID_LA:
- {
- Lamp *la = (Lamp *)owner_id;
- mtex = (MTex **)(&la->mtex);
- break;
- }
- case ID_WO:
- {
- World *wo = (World *)owner_id;
- mtex = (MTex **)(&wo->mtex);
- break;
- }
case ID_PA:
{
ParticleSettings *part = (ParticleSettings *)owner_id;
@@ -2121,10 +2135,6 @@ static size_t animdata_filter_ds_material(bAnimContext *ac, ListBase *anim_data,
/* material's animation data */
tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ma, filter_mode);
- /* textures */
- if (!(ads->filterflag & ADS_FILTER_NOTEX))
- tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)ma, filter_mode);
-
/* nodes */
if ((ma->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE))
tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)ma, ma->nodetree, filter_mode);
@@ -2443,10 +2453,6 @@ static size_t animdata_filter_ds_obdata(bAnimContext *ac, ListBase *anim_data, b
/* nodetree */
if ((ntree) && !(ads->filterflag & ADS_FILTER_NONTREE))
tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, &la->id, ntree, filter_mode);
-
- /* textures */
- if (!(ads->filterflag & ADS_FILTER_NOTEX))
- tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, &la->id, filter_mode);
break;
}
}
@@ -2608,8 +2614,10 @@ static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data
}
/* grease pencil */
- if ((ob->gpd) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) {
- tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->gpd, filter_mode);
+ if ((ob->type == OB_GPENCIL) &&
+ (ob->data) && !(ads->filterflag & ADS_FILTER_NOGPENCIL))
+ {
+ tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->data, filter_mode);
}
}
END_ANIMFILTER_SUBCHANNELS;
@@ -2621,7 +2629,7 @@ static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data
if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
/* check if filtering by selection */
// XXX: double-check on this - most of the time, a lot of tools need to filter out these channels!
- if (ANIMCHANNEL_SELOK((base->flag & SELECT))) {
+ if (ANIMCHANNEL_SELOK((base->flag & BASE_SELECTED))) {
/* check if filtering by active status */
if (ANIMCHANNEL_ACTIVEOK(ob)) {
ANIMCHANNEL_NEW_CHANNEL(base, ANIMTYPE_OBJECT, ob);
@@ -2651,10 +2659,6 @@ static size_t animdata_filter_ds_world(bAnimContext *ac, ListBase *anim_data, bD
/* animation data filtering */
tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)wo, filter_mode);
- /* textures for world */
- if (!(ads->filterflag & ADS_FILTER_NOTEX))
- tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)wo, filter_mode);
-
/* nodes */
if ((wo->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE))
tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)wo, wo->nodetree, filter_mode);
@@ -2845,7 +2849,7 @@ static size_t animdata_filter_dopesheet_movieclips(bAnimContext *ac, ListBase *a
}
/* Helper for animdata_filter_dopesheet() - For checking if an object should be included or not */
-static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base, int filter_mode)
+static bool animdata_filter_base_is_ok(bDopeSheet *ads, Base *base, int filter_mode)
{
Object *ob = base->object;
@@ -2863,7 +2867,7 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base
*/
if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
/* layer visibility - we check both object and base, since these may not be in sync yet */
- if ((scene->lay & (ob->lay | base->lay)) == 0)
+ if ((base->flag & BASE_VISIBLE) == 0)
return false;
/* outliner restrict-flag */
@@ -2898,7 +2902,7 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base
}
/* check selection and object type filters */
- if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/)) {
+ if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED) /*|| (base == sce->basact)*/)) {
/* only selected should be shown */
return false;
}
@@ -2907,8 +2911,8 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base
* objects by the grouped status is on
* - used to ease the process of doing multiple-character choreographies
*/
- if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) {
- if (BKE_group_object_exists(ads->filter_grp, ob) == 0)
+ if (ads->filter_grp != NULL) {
+ if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0)
return false;
}
@@ -2926,15 +2930,15 @@ static int ds_base_sorting_cmp(const void *base1_ptr, const void *base2_ptr)
}
/* Get a sorted list of all the bases - for inclusion in dopesheet (when drawing channels) */
-static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads, Scene *scene, int filter_mode, size_t *r_usable_bases)
+static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads, ViewLayer *view_layer, int filter_mode, size_t *r_usable_bases)
{
/* Create an array with space for all the bases, but only containing the usable ones */
- size_t tot_bases = BLI_listbase_count(&scene->base);
+ size_t tot_bases = BLI_listbase_count(&view_layer->object_bases);
size_t num_bases = 0;
Base **sorted_bases = MEM_mallocN(sizeof(Base *) * tot_bases, "Dopesheet Usable Sorted Bases");
- for (Base *base = scene->base.first; base; base = base->next) {
- if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (animdata_filter_base_is_ok(ads, base, filter_mode)) {
sorted_bases[num_bases++] = base;
}
}
@@ -2952,6 +2956,7 @@ static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads, Scene *scene, int
static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode)
{
Scene *scene = (Scene *)ads->source;
+ ViewLayer *view_layer = (ViewLayer *)ac->view_layer;
size_t items = 0;
/* check that we do indeed have a scene */
@@ -2990,14 +2995,14 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b
* - Don't do this if there's just a single object
*/
if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && !(ads->flag & ADS_FLAG_NO_DB_SORT) &&
- (scene->base.first != scene->base.last))
+ (view_layer->object_bases.first != view_layer->object_bases.last))
{
/* Filter list of bases (i.e. objects), sort them, then add their contents normally... */
// TODO: Cache the old sorted order - if the set of bases hasn't changed, don't re-sort...
Base **sorted_bases;
size_t num_bases;
- sorted_bases = animdata_filter_ds_sorted_bases(ads, scene, filter_mode, &num_bases);
+ sorted_bases = animdata_filter_ds_sorted_bases(ads, view_layer, filter_mode, &num_bases);
if (sorted_bases) {
/* Add the necessary channels for these bases... */
for (size_t i = 0; i < num_bases; i++) {
@@ -3014,8 +3019,8 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b
/* Filter and add contents of each base (i.e. object) without them sorting first
* NOTE: This saves performance in cases where order doesn't matter
*/
- for (Base *base = scene->base.first; base; base = base->next) {
- if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (animdata_filter_base_is_ok(ads, base, filter_mode)) {
/* since we're still here, this object should be usable */
items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode);
}
@@ -3258,6 +3263,15 @@ size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_F
}
+ /* Timeline Mode - Basically the same as dopesheet, except we only have the summary for now */
+ case ANIMCONT_TIMELINE:
+ {
+ /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */
+ if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
+ items += animdata_filter_dopesheet(ac, anim_data, data, filter_mode);
+ break;
+ }
+
/* Special/Internal Use */
case ANIMCONT_CHANNEL: /* animation channel */
{
diff --git a/source/blender/editors/animation/anim_intern.h b/source/blender/editors/animation/anim_intern.h
index 8f237652e77..73f2e85164b 100644
--- a/source/blender/editors/animation/anim_intern.h
+++ b/source/blender/editors/animation/anim_intern.h
@@ -79,6 +79,7 @@ void ANIM_OT_keying_set_active_set(struct wmOperatorType *ot);
/* Driver management operators for UI buttons (RMB menu) */
void ANIM_OT_driver_button_add(struct wmOperatorType *ot);
void ANIM_OT_driver_button_remove(struct wmOperatorType *ot);
+void ANIM_OT_driver_button_edit(struct wmOperatorType *ot);
void ANIM_OT_copy_driver_button(struct wmOperatorType *ot);
void ANIM_OT_paste_driver_button(struct wmOperatorType *ot);
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 05682292485..4d21ed8b5b4 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -36,13 +36,14 @@
#include "DNA_object_types.h"
#include "BLI_blenlib.h"
-#include "BLI_math_base.h"
+#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -56,9 +57,12 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "UI_view2d.h"
@@ -67,12 +71,15 @@
#include "ED_anim_api.h"
#include "ED_markers.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_util.h"
#include "ED_numinput.h"
#include "ED_object.h"
#include "ED_transform.h"
#include "ED_types.h"
+#include "DEG_depsgraph.h"
+
/* ************* Marker API **************** */
/* helper function for getting the list of markers to work on */
@@ -332,6 +339,44 @@ void debug_markers_print_list(ListBase *markers)
/* ************* Marker Drawing ************ */
+static void draw_marker_name(
+ const uiFontStyle *fstyle, TimeMarker *marker, const char *name,
+ int cfra, const float xpos, const float ypixels)
+{
+ unsigned char text_col[4];
+ float x, y;
+
+ /* minimal y coordinate which wouldn't be occluded by scroll */
+ int min_y = 17.0f * UI_DPI_FAC;
+
+ if (marker->flag & SELECT) {
+ UI_GetThemeColor4ubv(TH_TEXT_HI, text_col);
+ x = xpos + 4.0f * UI_DPI_FAC;
+ y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC;
+ y = max_ii(y, min_y);
+ }
+ else {
+ UI_GetThemeColor4ubv(TH_TEXT, text_col);
+ if ((marker->frame <= cfra) && (marker->frame + 5 > cfra)) {
+ x = xpos + 8.0f * UI_DPI_FAC;
+ y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC;
+ y = max_ii(y, min_y);
+ }
+ else {
+ x = xpos + 8.0f * UI_DPI_FAC;
+ y = 17.0f * UI_DPI_FAC;
+ }
+ }
+
+#ifdef DURIAN_CAMERA_SWITCH
+ if (marker->camera && (marker->camera->restrictflag & OB_RESTRICT_RENDER)) {
+ text_col[3] = 100;
+ }
+#endif
+
+ UI_fontstyle_draw_simple(fstyle, x, y, name, text_col);
+}
+
/* function to draw markers */
static void draw_marker(
View2D *v2d, const uiFontStyle *fstyle, TimeMarker *marker, int cfra, int flag,
@@ -339,10 +384,15 @@ static void draw_marker(
const float ypixels, const float xscale, const float yscale)
{
const float xpos = marker->frame * xscale;
+#ifdef DURIAN_CAMERA_SWITCH
+ const float yoffs = (marker->camera) ? 0.2f * UI_DPI_ICON_SIZE : 0.0f;
+#else
+ const float yoffs = 0.0f;
+#endif
int icon_id;
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
/* vertical line - dotted */
#ifdef DURIAN_CAMERA_SWITCH
@@ -351,19 +401,30 @@ static void draw_marker(
if (flag & DRAW_MARKERS_LINES)
#endif
{
- setlinestyle(3);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
- if (marker->flag & SELECT)
- glColor4ub(255, 255, 255, 96);
- else
- glColor4ub(0, 0, 0, 96);
+ if (marker->flag & SELECT) {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.38f);
+ }
+ else {
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.38f);
+ }
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
- glBegin(GL_LINES);
- glVertex2f(xpos + 0.5f, 12.0f);
- glVertex2f(xpos + 0.5f, (v2d->cur.ymax + 12.0f) * yscale);
- glEnd();
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, xpos + 0.5f, 12.0f);
+ immVertex2f(pos, xpos + 0.5f, (v2d->cur.ymax + 12.0f) * yscale);
+ immEnd();
- setlinestyle(0);
+ immUnbindProgram();
}
/* 5 px to offset icon to align properly, space / pixels corrects for zoom */
@@ -372,52 +433,35 @@ static void draw_marker(
(marker->flag & SELECT) ? ICON_PMARKER_SEL :
ICON_PMARKER;
}
+#ifdef DURIAN_CAMERA_SWITCH
+ else if (marker->camera) {
+ icon_id = (marker->flag & SELECT) ? ICON_OUTLINER_OB_CAMERA :
+ ICON_CAMERA_DATA;
+ }
+#endif
else {
icon_id = (marker->flag & SELECT) ? ICON_MARKER_HLT :
ICON_MARKER;
}
- UI_icon_draw(xpos - 0.45f * UI_DPI_ICON_SIZE, UI_DPI_ICON_SIZE, icon_id);
+ UI_icon_draw(xpos - 0.45f * UI_DPI_ICON_SIZE, yoffs + UI_DPI_ICON_SIZE, icon_id);
- glDisable(GL_BLEND);
+ GPU_blend(false);
/* and the marker name too, shifted slightly to the top-right */
- if (marker->name[0]) {
- float x, y;
-
- /* minimal y coordinate which wouldn't be occluded by scroll */
- int min_y = 17.0f * UI_DPI_FAC;
-
- if (marker->flag & SELECT) {
- UI_ThemeColor(TH_TEXT_HI);
- x = xpos + 4.0f * UI_DPI_FAC;
- y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC;
- y = max_ii(y, min_y);
- }
- else {
- UI_ThemeColor(TH_TEXT);
- if ((marker->frame <= cfra) && (marker->frame + 5 > cfra)) {
- x = xpos + 8.0f * UI_DPI_FAC;
- y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC;
- y = max_ii(y, min_y);
- }
- else {
- x = xpos + 8.0f * UI_DPI_FAC;
- y = 17.0f * UI_DPI_FAC;
- }
- }
-
#ifdef DURIAN_CAMERA_SWITCH
- if (marker->camera && (marker->camera->restrictflag & OB_RESTRICT_RENDER)) {
- float col[4];
- glGetFloatv(GL_CURRENT_COLOR, col);
- col[3] = 0.4;
- glColor4fv(col);
- }
-#endif
+ if (marker->camera) {
+ draw_marker_name(fstyle, marker, marker->camera->id.name + 2, cfra, xpos, ypixels);
+ }
+ else if (marker->name[0]) {
+ draw_marker_name(fstyle, marker, marker->name, cfra, xpos, ypixels);
+ }
+#else
+ if (marker->name[0]) {
+ draw_marker_name(fstyle, marker, marker->name, cfra, xpos, ypixels);
- UI_fontstyle_draw_simple(fstyle, x, y, marker->name);
}
+#endif
}
/* Draw Scene-Markers in time window */
@@ -443,21 +487,27 @@ void ED_markers_draw(const bContext *C, int flag)
v2d = UI_view2d_fromcontext(C);
if (flag & DRAW_MARKERS_MARGIN) {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
const unsigned char shade[4] = {0, 0, 0, 16};
- glColor4ubv(shade);
+ immUniformColor4ubv(shade);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- glRectf(v2d->cur.xmin, 0, v2d->cur.xmax, UI_MARKER_MARGIN_Y);
+ immRectf(pos, v2d->cur.xmin, 0, v2d->cur.xmax, UI_MARKER_MARGIN_Y);
- glDisable(GL_BLEND);
+ GPU_blend(false);
+
+ immUnbindProgram();
}
/* no time correction for framelen! space is drawn with old values */
ypixels = BLI_rcti_size_y(&v2d->mask);
UI_view2d_scale_get(v2d, &xscale, &yscale);
- glScalef(1.0f / xscale, 1.0f, 1.0f);
+ GPU_matrix_push();
+ GPU_matrix_scale_2f(1.0f / xscale, 1.0f);
/* x-bounds with offset for text (adjust for long string, avoid checking string width) */
font_width_max = (10 * UI_DPI_FAC) / xscale;
@@ -480,7 +530,7 @@ void ED_markers_draw(const bContext *C, int flag)
}
}
- glScalef(xscale, 1.0f, 1.0f);
+ GPU_matrix_pop();
}
/* ************************ Marker Wrappers API ********************* */
@@ -552,7 +602,6 @@ static bool ed_markers_poll_markers_exist(bContext *C)
static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, const wmEvent *event,
int (*invoke_func)(bContext *, wmOperator *, const wmEvent *))
{
- ScrArea *sa = CTX_wm_area(C);
int retval = OPERATOR_PASS_THROUGH;
/* removed check for Y coord of event, keymap has bounbox now */
@@ -565,12 +614,10 @@ static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, const wm
else
BKE_report(op->reports, RPT_ERROR, "Programming error: operator does not actually have code to do anything!");
- /* return status modifications - for now, make this spacetype dependent as above */
- if (sa->spacetype != SPACE_TIME) {
- /* unless successful, must add "pass-through" to let normal operator's have a chance at tackling this event */
- if ((retval & (OPERATOR_FINISHED | OPERATOR_INTERFACE)) == 0) {
- retval |= OPERATOR_PASS_THROUGH;
- }
+
+ /* unless successful, must add "pass-through" to let normal operator's have a chance at tackling this event */
+ if ((retval & (OPERATOR_FINISHED | OPERATOR_INTERFACE)) == 0) {
+ retval |= OPERATOR_PASS_THROUGH;
}
return retval;
@@ -672,8 +719,7 @@ typedef struct MarkerMove {
static bool ed_marker_move_use_time(MarkerMove *mm)
{
- if (((mm->slink->spacetype == SPACE_TIME) && !(((SpaceTime *)mm->slink)->flag & TIME_DRAWFRAMES)) ||
- ((mm->slink->spacetype == SPACE_SEQ) && !(((SpaceSeq *)mm->slink)->flag & SEQ_DRAWFRAMES)) ||
+ if (((mm->slink->spacetype == SPACE_SEQ) && !(((SpaceSeq *)mm->slink)->flag & SEQ_DRAWFRAMES)) ||
((mm->slink->spacetype == SPACE_ACTION) && (((SpaceAction *)mm->slink)->flag & SACTION_DRAWTIME)) ||
((mm->slink->spacetype == SPACE_IPO) && !(((SpaceIpo *)mm->slink)->flag & SIPO_DRAWTIME)) ||
((mm->slink->spacetype == SPACE_NLA) && !(((SpaceNla *)mm->slink)->flag & SNLA_DRAWTIME)))
@@ -725,7 +771,7 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op)
BLI_snprintf(str, sizeof(str), IFACE_("Marker offset %s"), str_offs);
}
- ED_area_headerprint(CTX_wm_area(C), str);
+ ED_area_status_text(CTX_wm_area(C), str);
}
/* copy selection to temp buffer */
@@ -785,7 +831,7 @@ static void ed_marker_move_exit(bContext *C, wmOperator *op)
op->customdata = NULL;
/* clear custom header prints */
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_area_status_text(CTX_wm_area(C), NULL);
}
static int ed_marker_move_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -844,7 +890,7 @@ static void ed_marker_move_apply(bContext *C, wmOperator *op)
BKE_scene_camera_switch_update(scene);
if (camera != scene->camera) {
- BKE_screen_view3d_scene_sync(sc);
+ BKE_screen_view3d_scene_sync(sc, scene);
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
}
#endif
@@ -917,10 +963,7 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *even
mm->evtx = event->x;
fac = ((float)(event->x - mm->firstx) * dx);
- if (mm->slink->spacetype == SPACE_TIME)
- apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0);
- else
- apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
+ apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
RNA_int_set(op->ptr, "frames", (int)fac);
ed_marker_move_apply(C, op);
@@ -1129,12 +1172,13 @@ static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool
if (camera) {
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Base *base;
TimeMarker *marker;
int sel = 0;
if (!extend)
- BKE_scene_base_deselect_all(scene);
+ BKE_view_layer_base_deselect_all(view_layer);
for (marker = markers->first; marker; marker = marker->next) {
if (marker->frame == cfra) {
@@ -1146,16 +1190,17 @@ static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool
for (marker = markers->first; marker; marker = marker->next) {
if (marker->camera) {
if (marker->frame == cfra) {
- base = BKE_scene_base_find(scene, marker->camera);
+ base = BKE_view_layer_base_find(view_layer, marker->camera);
if (base) {
- ED_base_object_select(base, sel);
+ ED_object_base_select(base, sel);
if (sel)
- ED_base_object_activate(C, base);
+ ED_object_base_activate(C, base);
}
}
}
}
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
#else
@@ -1208,7 +1253,7 @@ static void MARKER_OT_select(wmOperatorType *ot)
#endif
}
-/* *************************** border select markers **************** */
+/* *************************** box select markers **************** */
/* operator state vars used: (added by default WM callbacks)
* xmin, ymin
@@ -1229,7 +1274,7 @@ static void MARKER_OT_select(wmOperatorType *ot)
* poll() has to be filled in by user for context
*/
-static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
+static int ed_marker_box_select_exec(bContext *C, wmOperator *op)
{
View2D *v2d = UI_view2d_fromcontext(C);
ListBase *markers = ED_context_get_markers(C);
@@ -1265,23 +1310,23 @@ static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
return 1;
}
-static int ed_marker_select_border_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event)
+static int ed_marker_select_box_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event)
{
- return ed_markers_opwrap_invoke_custom(C, op, event, WM_gesture_border_invoke);
+ return ed_markers_opwrap_invoke_custom(C, op, event, WM_gesture_box_invoke);
}
-static void MARKER_OT_select_border(wmOperatorType *ot)
+static void MARKER_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Marker Border Select";
- ot->description = "Select all time markers using border selection";
- ot->idname = "MARKER_OT_select_border";
+ ot->name = "Marker Box Select";
+ ot->description = "Select all time markers using box selection";
+ ot->idname = "MARKER_OT_select_box";
/* api callbacks */
- ot->exec = ed_marker_border_select_exec;
- ot->invoke = ed_marker_select_border_invoke_wrapper;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->exec = ed_marker_box_select_exec;
+ ot->invoke = ed_marker_select_box_invoke_wrapper;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = ed_markers_poll_markers_exist;
@@ -1289,7 +1334,7 @@ static void MARKER_OT_select_border(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* rna */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
}
/* *********************** (de)select all ***************** */
@@ -1517,7 +1562,7 @@ static void MARKER_OT_make_links_scene(wmOperatorType *ot)
#ifdef DURIAN_CAMERA_SWITCH
/* ******************************* camera bind marker ***************** */
-static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op))
+static int ed_marker_camera_bind_exec(bContext *C, wmOperator *op)
{
bScreen *sc = CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
@@ -1525,15 +1570,37 @@ static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op))
ListBase *markers = ED_context_get_markers(C);
TimeMarker *marker;
- marker = ED_markers_get_first_selected(markers);
- if (marker == NULL)
+ /* Don't do anything if we don't have a camera selected */
+ if (ob == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Select a camera to bind to a marker on this frame");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* add new marker, unless we already have one on this frame, in which case, replace it */
+ if (markers == NULL)
return OPERATOR_CANCELLED;
+ marker = ED_markers_find_nearest_marker(markers, CFRA);
+ if ((marker == NULL) || (marker->frame != CFRA)) {
+ marker = MEM_callocN(sizeof(TimeMarker), "Camera TimeMarker");
+ marker->flag = SELECT;
+ marker->frame = CFRA;
+ BLI_addtail(markers, marker);
+
+ /* deselect all others, so that the user can then move it without problems */
+ for (TimeMarker *m = markers->first; m; m = m->next) {
+ if (m != marker) {
+ m->flag &= ~SELECT;
+ }
+ }
+ }
+
+ /* bind to the nominated camera (as set in operator props) */
marker->camera = ob;
/* camera may have changes */
BKE_scene_camera_switch_update(scene);
- BKE_screen_view3d_scene_sync(sc);
+ BKE_screen_view3d_scene_sync(sc, scene);
WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
@@ -1546,13 +1613,13 @@ static void MARKER_OT_camera_bind(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Bind Camera to Markers";
- ot->description = "Bind the active camera to selected marker(s)";
+ ot->description = "Bind the selected camera to a marker on the current frame";
ot->idname = "MARKER_OT_camera_bind";
/* api callbacks */
ot->exec = ed_marker_camera_bind_exec;
ot->invoke = ed_markers_opwrap_invoke;
- ot->poll = ed_markers_poll_selected_no_locked_markers;
+ ot->poll = ED_operator_animview_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1568,7 +1635,7 @@ void ED_operatortypes_marker(void)
WM_operatortype_append(MARKER_OT_move);
WM_operatortype_append(MARKER_OT_duplicate);
WM_operatortype_append(MARKER_OT_select);
- WM_operatortype_append(MARKER_OT_select_border);
+ WM_operatortype_append(MARKER_OT_select_box);
WM_operatortype_append(MARKER_OT_select_all);
WM_operatortype_append(MARKER_OT_delete);
WM_operatortype_append(MARKER_OT_rename);
@@ -1581,47 +1648,5 @@ void ED_operatortypes_marker(void)
/* called in screen_ops.c:ED_keymap_screen() */
void ED_keymap_marker(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Markers", 0, 0);
- wmKeyMapItem *kmi;
-
- WM_keymap_verify_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "MARKER_OT_move", EVT_TWEAK_S, KM_ANY, 0, 0);
- WM_keymap_verify_item(keymap, "MARKER_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_verify_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
-
-#ifdef DURIAN_CAMERA_SWITCH
- kmi = WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "camera", true);
-
- kmi = WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "camera", true);
-#else
- (void)kmi;
-#endif
-
- WM_keymap_verify_item(keymap, "MARKER_OT_select_border", BKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "MARKER_OT_select_all", AKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MARKER_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MARKER_OT_delete", DELKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "MARKER_OT_move", GKEY, KM_PRESS, 0, 0);
-#ifdef DURIAN_CAMERA_SWITCH
- WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0);
-#endif
-}
-
-/* to be called from animation editor keymaps, see note below */
-void ED_marker_keymap_animedit_conflictfree(wmKeyMap *keymap)
-{
- /* duplicate of some marker-hotkeys but without the bounds checking
- * since these are handy to be able to do unrestricted and won't conflict
- * with primary function hotkeys (Usability tweak [#27469])
- */
- WM_keymap_add_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_ensure(keyconf, "Markers", 0, 0);
}
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 068d1c80f9b..f6fdd539983 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -76,7 +76,7 @@ static bool change_frame_poll(bContext *C)
* this shouldn't show up in 3D editor (or others without 2D timeline view) via search
*/
if (sa) {
- if (ELEM(sa->spacetype, SPACE_TIME, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
+ if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
return true;
}
else if (sa->spacetype == SPACE_IPO) {
@@ -87,7 +87,7 @@ static bool change_frame_poll(bContext *C)
}
}
- CTX_wm_operator_poll_msg_set(C, "Expected an timeline/animation area to be active");
+ CTX_wm_operator_poll_msg_set(C, "Expected an animation area to be active");
return false;
}
@@ -282,6 +282,116 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+
+/* ****************** Start/End Frame Operators *******************************/
+
+static bool anim_set_end_frames_poll(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ /* XXX temp? prevent changes during render */
+ if (G.is_rendering) return false;
+
+ /* although it's only included in keymaps for regions using ED_KEYMAP_ANIMATION,
+ * this shouldn't show up in 3D editor (or others without 2D timeline view) via search
+ */
+ if (sa) {
+ if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
+ return true;
+ }
+ }
+
+ CTX_wm_operator_poll_msg_set(C, "Expected an animation area to be active");
+ return false;
+}
+
+static int anim_set_sfra_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ int frame;
+
+ if (scene == NULL)
+ return OPERATOR_CANCELLED;
+
+ frame = CFRA;
+
+ /* if Preview Range is defined, set the 'start' frame for that */
+ if (PRVRANGEON)
+ scene->r.psfra = frame;
+ else
+ scene->r.sfra = frame;
+
+ if (PEFRA < frame) {
+ if (PRVRANGEON)
+ scene->r.pefra = frame;
+ else
+ scene->r.efra = frame;
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ANIM_OT_start_frame_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Start Frame";
+ ot->idname = "ANIM_OT_start_frame_set";
+ ot->description = "Set the current frame as the preview or scene start frame";
+
+ /* api callbacks */
+ ot->exec = anim_set_sfra_exec;
+ ot->poll = anim_set_end_frames_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int anim_set_efra_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ int frame;
+
+ if (scene == NULL)
+ return OPERATOR_CANCELLED;
+
+ frame = CFRA;
+
+ /* if Preview Range is defined, set the 'end' frame for that */
+ if (PRVRANGEON)
+ scene->r.pefra = frame;
+ else
+ scene->r.efra = frame;
+
+ if (PSFRA > frame) {
+ if (PRVRANGEON)
+ scene->r.psfra = frame;
+ else
+ scene->r.sfra = frame;
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ANIM_OT_end_frame_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set End Frame";
+ ot->idname = "ANIM_OT_end_frame_set";
+ ot->description = "Set the current frame as the preview or scene end frame";
+
+ /* api callbacks */
+ ot->exec = anim_set_efra_exec;
+ ot->poll = anim_set_end_frames_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ****************** set preview range operator ****************************/
static int previewrange_define_exec(bContext *C, wmOperator *op)
@@ -291,7 +401,7 @@ static int previewrange_define_exec(bContext *C, wmOperator *op)
float sfra, efra;
rcti rect;
- /* get min/max values from border select rect (already in region coordinates, not screen) */
+ /* get min/max values from box select rect (already in region coordinates, not screen) */
WM_operator_properties_border_to_rcti(op, &rect);
/* convert min/max values to frames (i.e. region to 'tot' rect) */
@@ -324,10 +434,10 @@ static void ANIM_OT_previewrange_set(wmOperatorType *ot)
ot->description = "Interactively define frame range used for playback";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
+ ot->invoke = WM_gesture_box_invoke;
ot->exec = previewrange_define_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = ED_operator_animview_active;
@@ -338,7 +448,7 @@ static void ANIM_OT_previewrange_set(wmOperatorType *ot)
/* used to define frame range.
*
* note: border Y values are not used,
- * but are needed by borderselect gesture operator stuff */
+ * but are needed by box_select gesture operator stuff */
WM_operator_properties_border(ot);
}
@@ -389,6 +499,9 @@ void ED_operatortypes_anim(void)
/* Animation Editors only -------------------------- */
WM_operatortype_append(ANIM_OT_change_frame);
+ WM_operatortype_append(ANIM_OT_start_frame_set);
+ WM_operatortype_append(ANIM_OT_end_frame_set);
+
WM_operatortype_append(ANIM_OT_previewrange_set);
WM_operatortype_append(ANIM_OT_previewrange_clear);
@@ -405,6 +518,7 @@ void ED_operatortypes_anim(void)
WM_operatortype_append(ANIM_OT_driver_button_add);
WM_operatortype_append(ANIM_OT_driver_button_remove);
+ WM_operatortype_append(ANIM_OT_driver_button_edit);
WM_operatortype_append(ANIM_OT_copy_driver_button);
WM_operatortype_append(ANIM_OT_paste_driver_button);
@@ -422,17 +536,5 @@ void ED_operatortypes_anim(void)
void ED_keymap_anim(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Animation", 0, 0);
- wmKeyMapItem *kmi;
-
- /* frame management */
- /* NOTE: 'ACTIONMOUSE' not 'LEFTMOUSE', as user may have swapped mouse-buttons */
- WM_keymap_add_item(keymap, "ANIM_OT_change_frame", ACTIONMOUSE, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TKEY, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.show_seconds");
-
- /* preview range */
- WM_keymap_verify_item(keymap, "ANIM_OT_previewrange_set", PKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "ANIM_OT_previewrange_clear", PKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_ensure(keyconf, "Animation", 0, 0);
}
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index ebe085cd006..85e58521493 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -41,14 +41,17 @@
#include "DNA_anim_types.h"
#include "DNA_object_types.h"
+#include "DNA_space_types.h"
#include "DNA_texture_types.h"
#include "BKE_animsys.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_context.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_keyframing.h"
#include "UI_interface.h"
@@ -115,7 +118,6 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
/* add some new driver data */
fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
- fcu->driver->flag |= DRIVER_FLAG_SHOWDEBUG;
/* F-Modifier or Keyframes? */
// FIXME: replace these magic numbers with defines
@@ -412,13 +414,20 @@ int ANIM_add_driver(ReportList *reports, ID *id, const char rna_path[], int arra
/* set the type of the driver */
driver->type = type;
- /* creating drivers for buttons will create the driver(s) with type
+ /* Creating drivers for buttons will create the driver(s) with type
* "scripted expression" so that their values won't be lost immediately,
* so here we copy those values over to the driver's expression
+ *
+ * If the "default dvar" option (for easier UI setup of drivers) is provided,
+ * include "var" in the expressions too, so that the user doesn't have to edit
+ * it to get something to happen. It should be fine to just add it to the default
+ * value, so that we get both in the expression, even if it's a bit more confusing
+ * that way...
*/
if (type == DRIVER_TYPE_PYTHON) {
PropertyType proptype = RNA_property_type(prop);
int array = RNA_property_array_length(&ptr, prop);
+ const char *dvar_prefix = (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) ? "var + " : "";
char *expression = driver->expression;
int val, maxlen = sizeof(driver->expression);
float fval;
@@ -427,19 +436,23 @@ int ANIM_add_driver(ReportList *reports, ID *id, const char rna_path[], int arra
if (!array) val = RNA_property_boolean_get(&ptr, prop);
else val = RNA_property_boolean_get_index(&ptr, prop, array_index);
- BLI_strncpy(expression, (val) ? "True" : "False", maxlen);
+ BLI_snprintf(expression, maxlen, "%s%s", dvar_prefix, (val) ? "True" : "False");
}
else if (proptype == PROP_INT) {
if (!array) val = RNA_property_int_get(&ptr, prop);
else val = RNA_property_int_get_index(&ptr, prop, array_index);
- BLI_snprintf(expression, maxlen, "%d", val);
+ BLI_snprintf(expression, maxlen, "%s%d", dvar_prefix, val);
}
else if (proptype == PROP_FLOAT) {
if (!array) fval = RNA_property_float_get(&ptr, prop);
else fval = RNA_property_float_get_index(&ptr, prop, array_index);
- BLI_snprintf(expression, maxlen, "%.3f", fval);
+ BLI_snprintf(expression, maxlen, "%s%.3f", dvar_prefix, fval);
+ BLI_str_rstrip_float_zero(expression, '\0');
+ }
+ else if (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) {
+ BLI_strncpy(expression, "var", maxlen);
}
}
@@ -732,11 +745,8 @@ bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
driver->variables.last = tmp_list.last;
}
-#ifdef WITH_PYTHON
/* since driver variables are cached, the expression needs re-compiling too */
- if (driver->type == DRIVER_TYPE_PYTHON)
- driver->flag |= DRIVER_FLAG_RENAMEVAR;
-#endif
+ BKE_driver_invalidate_expression(driver, false, true);
return true;
}
@@ -750,7 +760,7 @@ bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
/* NOTE: Used by ANIM_OT_driver_button_add and UI_OT_eyedropper_driver */
// XXX: These names need reviewing
EnumPropertyItem prop_driver_create_mapping_types[] = {
- {CREATEDRIVER_MAPPING_1_N, "SINGLE_MANY", ICON_UI, "All from Target",
+ {CREATEDRIVER_MAPPING_1_N, "SINGLE_MANY", 0, "All from Target",
"Drive all components of this property using the target picked"},
{CREATEDRIVER_MAPPING_1_1, "DIRECT", 0, "Single from Target",
"Drive this component of this property using the target picked"},
@@ -804,7 +814,7 @@ static const EnumPropertyItem *driver_mapping_type_itemsf(bContext *C, PointerRN
}
-/* Add Driver Button Operator ------------------------ */
+/* Add Driver (With Menu) Button Operator ------------------------ */
static bool add_driver_button_poll(bContext *C)
{
@@ -843,7 +853,7 @@ static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_typ
if (success) {
/* send updates */
UI_context_update_anim_flag(C);
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
return OPERATOR_FINISHED;
@@ -853,7 +863,7 @@ static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_typ
}
}
-static int add_driver_button_exec(bContext *C, wmOperator *op)
+static int add_driver_button_menu_exec(bContext *C, wmOperator *op)
{
short mapping_type = RNA_enum_get(op->ptr, "mapping_type");
if (ELEM(mapping_type, CREATEDRIVER_MAPPING_NONE, CREATEDRIVER_MAPPING_NONE_ALL)) {
@@ -872,13 +882,13 @@ static int add_driver_button_exec(bContext *C, wmOperator *op)
}
/* Show menu or create drivers */
-static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int add_driver_button_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
PropertyRNA *prop;
if ((prop = RNA_struct_find_property(op->ptr, "mapping_type")) && RNA_property_is_set(op->ptr, prop)) {
/* Mapping Type is Set - Directly go into creating drivers */
- return add_driver_button_exec(C, op);
+ return add_driver_button_menu_exec(C, op);
}
else {
/* Show menu */
@@ -888,19 +898,16 @@ static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *
}
}
-void ANIM_OT_driver_button_add(wmOperatorType *ot)
+static void UNUSED_FUNCTION(ANIM_OT_driver_button_add_menu)(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Driver";
- ot->idname = "ANIM_OT_driver_button_add";
+ ot->name = "Add Driver Menu";
+ ot->idname = "ANIM_OT_driver_button_add_menu";
ot->description = "Add driver(s) for the property(s) represented by the highlighted button";
/* callbacks */
- /* NOTE: No exec, as we need all these to use the current context info
- * (especially the eyedropper, which is interactive)
- */
- ot->invoke = add_driver_button_invoke;
- ot->exec = add_driver_button_exec;
+ ot->invoke = add_driver_button_menu_invoke;
+ ot->exec = add_driver_button_menu_exec;
ot->poll = add_driver_button_poll;
/* flags */
@@ -912,6 +919,60 @@ void ANIM_OT_driver_button_add(wmOperatorType *ot)
RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf);
}
+/* Add Driver Button Operator ------------------------ */
+
+static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
+ int index;
+
+ /* try to find driver using property retrieved from UI */
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
+ /* 1) Create a new "empty" driver for this property */
+ char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
+ short success = 0;
+
+ if (path) {
+ success += ANIM_add_driver(op->reports, ptr.id.data, path, index, flags, DRIVER_TYPE_PYTHON);
+ MEM_freeN(path);
+ }
+
+ if (success) {
+ /* send updates */
+ UI_context_update_anim_flag(C);
+ DEG_id_tag_update(ptr.id.data, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(CTX_data_main(C));
+ WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL);
+ }
+
+ /* 2) Show editing panel for setting up this driver */
+ /* TODO: Use a different one from the editing popever, so we can have the single/all toggle? */
+ UI_popover_panel_invoke(C, "GRAPH_PT_drivers_popover", true, op->reports);
+ }
+
+ return OPERATOR_INTERFACE;
+}
+
+void ANIM_OT_driver_button_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Driver";
+ ot->idname = "ANIM_OT_driver_button_add";
+ ot->description = "Add driver for the property under the cursor";
+
+ /* callbacks */
+ /* NOTE: No exec, as we need all these to use the current context info */
+ ot->invoke = add_driver_button_invoke;
+ ot->poll = add_driver_button_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
+
/* Remove Driver Button Operator ------------------------ */
static int remove_driver_button_exec(bContext *C, wmOperator *op)
@@ -941,7 +1002,7 @@ static int remove_driver_button_exec(bContext *C, wmOperator *op)
if (success) {
/* send updates */
UI_context_update_anim_flag(C);
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
}
@@ -966,6 +1027,39 @@ void ANIM_OT_driver_button_remove(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "all", 1, "All", "Delete drivers for all elements of the array");
}
+/* Edit Driver Button Operator ------------------------ */
+
+static int edit_driver_button_exec(bContext *C, wmOperator *op)
+{
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
+ int index;
+
+ /* try to find driver using property retrieved from UI */
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ if (ptr.id.data && ptr.data && prop) {
+ UI_popover_panel_invoke(C, "GRAPH_PT_drivers_popover", true, op->reports);
+ }
+
+ return OPERATOR_INTERFACE;
+}
+
+void ANIM_OT_driver_button_edit(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Edit Driver";
+ ot->idname = "ANIM_OT_driver_button_edit";
+ ot->description = "Edit the drivers for the property connected represented by the highlighted button";
+
+ /* callbacks */
+ ot->exec = edit_driver_button_exec;
+ //op->poll = ??? // TODO: need to have some driver to be able to do this...
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
+
/* Copy Driver Button Operator ------------------------ */
static int copy_driver_button_exec(bContext *C, wmOperator *op)
@@ -1031,8 +1125,8 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op)
UI_context_update_anim_flag(C);
- DAG_relations_tag_update(CTX_data_main(C));
- DAG_id_tag_update(ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_relations_tag_update(CTX_data_main(C));
+ DEG_id_tag_update(ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); // XXX
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 54e0839d802..72da71a8a0e 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -42,17 +42,21 @@
#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"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_brush_types.h"
#include "DNA_mask_types.h"
#include "BKE_fcurve.h"
-#include "BIF_gl.h"
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -64,6 +68,16 @@
/* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
+BLI_INLINE bool is_cfra_eq(float a, float b)
+{
+ return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH);
+}
+
+BLI_INLINE bool is_cfra_lt(float a, float b)
+{
+ return (b - a) > BEZT_BINARYSEARCH_THRESH;
+}
+
/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
/* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */
short compare_ak_cfraPtr(void *node, void *data)
@@ -72,63 +86,158 @@ short compare_ak_cfraPtr(void *node, void *data)
const float *cframe = data;
float val = *cframe;
- if (IS_EQT(val, ak->cfra, BEZT_BINARYSEARCH_THRESH))
+ if (is_cfra_eq(val, ak->cfra))
return 0;
if (val < ak->cfra)
return -1;
- else if (val > ak->cfra)
- return 1;
else
- return 0;
+ return 1;
}
/* --------------- */
-/* 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)
{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- BezTriple *bezt = (BezTriple *)data;
+ BezTripleChain *chain = data;
- if (bezt->vec[1][0] < ak->cfra)
- return -1;
- else if (bezt->vec[1][0] > ak->cfra)
- return 1;
- else
- return 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 = 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);
- /* set 'modified', since this is used to identify long keyframes */
- ak->modified = 1;
+ /* count keyframes in this column */
+ ak->totkey = 1;
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;
+ ActKeyColumn *ak = node;
+ BezTripleChain *chain = data;
+ BezTriple *bezt = chain->cur;
/* set selection status and 'touched' status */
if (BEZT_ISSEL_ANY(bezt)) ak->sel = SELECT;
- ak->modified += 1;
+
+ /* count keyframes in this column */
+ ak->totkey++;
/* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */
if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME)
ak->key_type = BEZT_KEYTYPE_KEYFRAME;
+
+ /* For interpolation type, select the highest value (enum is sorted). */
+ ak->handle_type = MAX2(ak->handle_type, bezt_handle_type(bezt));
+
+ /* For extremes, detect when combining different states. */
+ char new_extreme = bezt_extreme_type(chain);
+
+ if (new_extreme != ak->extreme_type) {
+ /* Replace the flat status without adding mixed. */
+ if (ak->extreme_type == KEYFRAME_EXTREME_FLAT) {
+ ak->extreme_type = new_extreme;
+ }
+ else if (new_extreme != KEYFRAME_EXTREME_FLAT) {
+ ak->extreme_type |= (new_extreme | KEYFRAME_EXTREME_MIXED);
+ }
+ }
}
/* ......... */
@@ -136,15 +245,10 @@ static void nupdate_ak_bezt(void *node, void *data)
/* Comparator callback used for ActKeyColumns and GPencil frame */
static short compare_ak_gpframe(void *node, void *data)
{
- ActKeyColumn *ak = (ActKeyColumn *)node;
bGPDframe *gpf = (bGPDframe *)data;
- if (gpf->framenum < ak->cfra)
- return -1;
- else if (gpf->framenum > ak->cfra)
- return 1;
- else
- return 0;
+ float frame = gpf->framenum;
+ return compare_ak_cfraPtr(node, &frame);
}
/* New node callback used for building ActKeyColumns from GPencil frames */
@@ -158,8 +262,8 @@ static DLRBT_Node *nalloc_ak_gpframe(void *data)
ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0;
ak->key_type = gpf->key_type;
- /* set 'modified', since this is used to identify long keyframes */
- ak->modified = 1;
+ /* count keyframes in this column */
+ ak->totkey = 1;
return (DLRBT_Node *)ak;
}
@@ -172,7 +276,9 @@ static void nupdate_ak_gpframe(void *node, void *data)
/* set selection status and 'touched' status */
if (gpf->flag & GP_FRAME_SELECT) ak->sel = SELECT;
- ak->modified += 1;
+
+ /* count keyframes in this column */
+ ak->totkey++;
/* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */
if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME)
@@ -184,15 +290,10 @@ static void nupdate_ak_gpframe(void *node, void *data)
/* Comparator callback used for ActKeyColumns and GPencil frame */
static short compare_ak_masklayshape(void *node, void *data)
{
- ActKeyColumn *ak = (ActKeyColumn *)node;
MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
- if (masklay_shape->frame < ak->cfra)
- return -1;
- else if (masklay_shape->frame > ak->cfra)
- return 1;
- else
- return 0;
+ float frame = masklay_shape->frame;
+ return compare_ak_cfraPtr(node, &frame);
}
/* New node callback used for building ActKeyColumns from GPencil frames */
@@ -205,8 +306,8 @@ static DLRBT_Node *nalloc_ak_masklayshape(void *data)
ak->cfra = masklay_shape->frame;
ak->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? SELECT : 0;
- /* set 'modified', since this is used to identify long keyframes */
- ak->modified = 1;
+ /* count keyframes in this column */
+ ak->totkey = 1;
return (DLRBT_Node *)ak;
}
@@ -219,14 +320,16 @@ static void nupdate_ak_masklayshape(void *node, void *data)
/* set selection status and 'touched' status */
if (masklay_shape->flag & MASK_SHAPE_SELECT) ak->sel = SELECT;
- ak->modified += 1;
+
+ /* count keyframes in this column */
+ ak->totkey++;
}
/* --------------- */
/* Add the given BezTriple to the given 'list' of Keyframes */
-static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTriple *bezt)
+static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTripleChain *bezt)
{
if (ELEM(NULL, keys, bezt))
return;
@@ -254,64 +357,11 @@ static void add_masklay_to_keycolumns_list(DLRBT_Tree *keys, MaskLayerShape *mas
/* ActKeyBlocks (Long Keyframes) ------------------------------------------ */
-/* Comparator callback used for ActKeyBlock and cframe float-value pointer */
-/* NOTE: this is exported to other modules that use the ActKeyBlocks for finding long-keyframes */
-short compare_ab_cfraPtr(void *node, void *data)
-{
- ActKeyBlock *ab = (ActKeyBlock *)node;
- const float *cframe = data;
- float val = *cframe;
+static const ActKeyBlockInfo dummy_keyblock = { 0 };
- if (val < ab->start)
- return -1;
- else if (val > ab->start)
- return 1;
- else
- return 0;
-}
-
-/* --------------- */
-
-/* Create a ActKeyColumn for a pair of BezTriples */
-static ActKeyBlock *bezts_to_new_actkeyblock(BezTriple *prev, BezTriple *beztn)
+static void compute_keyblock_data(ActKeyBlockInfo *info, BezTriple *prev, BezTriple *beztn)
{
- ActKeyBlock *ab = MEM_callocN(sizeof(ActKeyBlock), "ActKeyBlock");
-
- ab->start = prev->vec[1][0];
- ab->end = beztn->vec[1][0];
- ab->val = beztn->vec[1][1];
-
- ab->sel = (BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn)) ? SELECT : 0;
- ab->modified = 1;
-
- if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD)
- ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD;
-
- return ab;
-}
-
-static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt, BezTriple *beztn)
-{
- ActKeyBlock *new_ab = NULL;
- BezTriple *prev = NULL;
-
- /* get the BezTriple immediately before the given one which has the same value */
- if (beztn != first_bezt) {
- /* XXX: Unless I'm overlooking some details from the past, this should be sufficient?
- * The old code did some elaborate stuff trying to find keyframe columns for
- * the given BezTriple, then step backwards to the column before that, and find
- * an appropriate BezTriple with matching values there. Maybe that was warranted
- * in the past, but now, that list is only ever filled with keyframes from the
- * current FCurve.
- *
- * -- Aligorith (20140415)
- */
- prev = beztn - 1;
- }
-
-
- /* check if block needed */
- if (prev == NULL) return;
+ memset(info, 0, sizeof(ActKeyBlockInfo));
if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) {
/* Animator tagged a "moving hold"
@@ -319,191 +369,182 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt
* we're just dealing with the first of a pair, and we don't
* want to be creating any phantom holds...
*/
- if (BEZKEYTYPE(prev) != BEZT_KEYTYPE_MOVEHOLD)
- return;
+ if (BEZKEYTYPE(prev) == BEZT_KEYTYPE_MOVEHOLD) {
+ info->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
+ }
}
- else {
- /* Check for same values...
- * - Handles must have same central value as each other
- * - Handles which control that section of the curve must be constant
- */
- if (IS_EQF(beztn->vec[1][1], prev->vec[1][1]) == 0) return;
- if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) == 0) return;
- if (IS_EQF(prev->vec[1][1], prev->vec[2][1]) == 0) return;
+ /* Check for same values...
+ * - Handles must have same central value as each other
+ * - Handles which control that section of the curve must be constant
+ */
+ if (IS_EQF(beztn->vec[1][1], prev->vec[1][1])) {
+ bool hold;
+
+ /* Only check handles in case of actual bezier interpolation. */
+ if (prev->ipo == BEZT_IPO_BEZ) {
+ hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) && IS_EQF(prev->vec[1][1], prev->vec[2][1]);
+ }
+ /* This interpolation type induces movement even between identical keys. */
+ else {
+ hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC);
+ }
+
+ if (hold) {
+ info->flag |= ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
+ }
}
- /* if there are no blocks already, just add as root */
- if (blocks->root == NULL) {
- /* just add this as the root, then call the tree-balancing functions to validate */
- new_ab = bezts_to_new_actkeyblock(prev, beztn);
- blocks->root = (DLRBT_Node *)new_ab;
+ /* Remember non-bezier interpolation info. */
+ if (prev->ipo != BEZT_IPO_BEZ) {
+ info->flag |= ACTKEYBLOCK_FLAG_NON_BEZIER;
}
+
+ info->sel = BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn);
+}
+
+static void add_keyblock_info(ActKeyColumn *col, const ActKeyBlockInfo *block)
+{
+ /* New curve and block. */
+ if (col->totcurve <= 1 && col->totblock == 0) {
+ memcpy(&col->block, block, sizeof(ActKeyBlockInfo));
+ }
+ /* Existing curve. */
else {
- ActKeyBlock *ab, *abn = NULL;
+ col->block.conflict |= (col->block.flag ^ block->flag);
+ col->block.flag |= block->flag;
+ col->block.sel |= block->sel;
+ }
- /* try to find a keyblock that starts on the previous beztriple, and add a new one if none start there
- * Note: we perform a tree traversal here NOT a standard linked-list traversal...
- * Note: we can't search from end to try to optimize this as it causes errors there's
- * an A ___ B |---| B situation
- */
- // FIXME: here there is a bug where we are trying to get the summary for the following channels
- // A|--------------|A ______________ B|--------------|B
- // A|------------------------------------------------|A
- // A|----|A|---|A|-----------------------------------|A
- for (ab = blocks->root; ab; ab = abn) {
- /* check if this is a match, or whether we go left or right
- * NOTE: we now use a float threshold to prevent precision errors causing problems with summaries
- */
- if (IS_EQT(ab->start, prev->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
- /* set selection status and 'touched' status */
- if (BEZT_ISSEL_ANY(beztn))
- ab->sel = SELECT;
+ if (block->flag) {
+ col->totblock++;
+ }
+}
- /* XXX: only when the first one was a moving hold? */
- if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD)
- ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD;
+static void add_bezt_to_keyblocks_list(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
+{
+ ActKeyColumn *col = keys->first;
- ab->modified++;
+ if (bezt && bezt_len >= 2) {
+ ActKeyBlockInfo block;
- /* done... no need to insert */
- return;
- }
- else {
- ActKeyBlock **abnp = NULL; /* branch to go down - used to hook new blocks to parents */
-
- /* check if go left or right, but if not available, add new node */
- if (ab->start < prev->vec[1][0])
- abnp = &ab->right;
- else
- abnp = &ab->left;
-
- /* if this does not exist, add a new node, otherwise continue... */
- if (*abnp == NULL) {
- /* add a new node representing this, and attach it to the relevant place */
- new_ab = bezts_to_new_actkeyblock(prev, beztn);
- new_ab->parent = ab;
- *abnp = new_ab;
- break;
+ /* Find the first key column while inserting dummy blocks. */
+ for (; col != NULL && is_cfra_lt(col->cfra, bezt[0].vec[1][0]); col = col->next) {
+ add_keyblock_info(col, &dummy_keyblock);
+ }
+
+ BLI_assert(col != NULL);
+
+ /* Insert real blocks. */
+ for (int v = 1; col != NULL && v < bezt_len; v++, bezt++) {
+ /* Wrong order of bezier keys: resync position. */
+ if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) {
+ /* Backtrack to find the right location. */
+ if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) {
+ ActKeyColumn *newcol = (ActKeyColumn *)BLI_dlrbTree_search_exact(
+ keys, compare_ak_cfraPtr, &bezt[1].vec[1][0]);
+
+ if (newcol != NULL) {
+ col = newcol;
+
+ /* The previous keyblock is garbage too. */
+ if (col->prev != NULL) {
+ add_keyblock_info(col->prev, &dummy_keyblock);
+ }
+ }
+ else {
+ BLI_assert(false);
+ }
}
- else
- abn = *abnp;
+
+ continue;
+ }
+
+ /* Normal sequence */
+ BLI_assert(is_cfra_eq(col->cfra, bezt[0].vec[1][0]));
+
+ compute_keyblock_data(&block, bezt, bezt + 1);
+
+ for (; col != NULL && is_cfra_lt(col->cfra, bezt[1].vec[1][0]); col = col->next) {
+ add_keyblock_info(col, &block);
}
+
+ BLI_assert(col != NULL);
}
}
- /* now, balance the tree taking into account this newly added node */
- BLI_dlrbTree_insert(blocks, (DLRBT_Node *)new_ab);
+ /* Insert dummy blocks at the end. */
+ for (; col != NULL; col = col->next) {
+ add_keyblock_info(col, &dummy_keyblock);
+ }
}
-/* --------- */
-
-/* Handle the 'touched' status of ActKeyColumn tree nodes */
-static void set_touched_actkeycolumn(ActKeyColumn *ak)
+/* Walk through columns and propagate blocks and totcurve.
+ *
+ * This must be called even by animation sources that don't generate
+ * keyblocks to keep the data structure consistent after adding columns.
+ */
+static void update_keyblocks(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
{
- /* sanity check */
- if (ak == NULL)
- return;
+ /* Recompute the prev/next linked list. */
+ BLI_dlrbTree_linkedlist_sync(keys);
+
+ /* Find the curve count */
+ int max_curve = 0;
- /* deal with self first */
- if (ak->modified) {
- ak->modified = 0;
- ak->totcurve++;
+ for (ActKeyColumn *col = keys->first; col; col = col->next) {
+ max_curve = MAX2(max_curve, col->totcurve);
}
- /* children */
- set_touched_actkeycolumn(ak->left);
- set_touched_actkeycolumn(ak->right);
-}
+ /* Propagate blocks to inserted keys */
+ ActKeyColumn *prev_ready = NULL;
-/* Handle the 'touched' status of ActKeyBlock tree nodes */
-static void set_touched_actkeyblock(ActKeyBlock *ab)
-{
- /* sanity check */
- if (ab == NULL)
- return;
+ for (ActKeyColumn *col = keys->first; col; col = col->next) {
+ /* Pre-existing column. */
+ if (col->totcurve > 0) {
+ prev_ready = col;
+ }
+ /* Newly inserted column, so copy block data from previous. */
+ else if (prev_ready != NULL) {
+ col->totblock = prev_ready->totblock;
+ memcpy(&col->block, &prev_ready->block, sizeof(ActKeyBlockInfo));
+ }
- /* deal with self first */
- if (ab->modified) {
- ab->modified = 0;
- ab->totcurve++;
+ col->totcurve = max_curve + 1;
}
- /* children */
- set_touched_actkeyblock(ab->left);
- set_touched_actkeyblock(ab->right);
+ /* Add blocks on top */
+ add_bezt_to_keyblocks_list(keys, bezt, bezt_len);
}
/* --------- */
-/* Checks if ActKeyBlock should exist... */
-bool actkeyblock_is_valid(ActKeyBlock *ab, DLRBT_Tree *keys)
+bool actkeyblock_is_valid(ActKeyColumn *ac)
{
- ActKeyColumn *ak;
- short startCurves, endCurves, totCurves;
+ 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 (ab == NULL)
+ if (!actkeyblock_is_valid(ac))
return 0;
- /* find out how many curves occur at each keyframe */
- ak = (ActKeyColumn *)BLI_dlrbTree_search_exact(keys, compare_ak_cfraPtr, &ab->start);
- startCurves = (ak) ? ak->totcurve : 0;
-
- ak = (ActKeyColumn *)BLI_dlrbTree_search_exact(keys, compare_ak_cfraPtr, &ab->end);
- endCurves = (ak) ? ak->totcurve : 0;
-
- /* only draw keyblock if it appears in at all of the keyframes at lowest end */
- if (!startCurves && !endCurves)
- return 0;
-
- totCurves = (startCurves > endCurves) ? endCurves : startCurves;
- return (ab->totcurve >= totCurves);
+ const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD);
+ return (ac->block.flag & ~ac->block.conflict) & hold_mask;
}
/* *************************** Keyframe Drawing *************************** */
-/* coordinates for diamond shape */
-static const float _unit_diamond_shape[4][2] = {
- {0.0f, 1.0f}, /* top vert */
- {1.0f, 0.0f}, /* mid-right */
- {0.0f, -1.0f}, /* bottom vert */
- {-1.0f, 0.0f} /* mid-left */
-};
-
-/* draw a simple diamond shape with OpenGL */
-void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, short key_type, short mode, float alpha)
+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 flags_id, short handle_type, short extreme_type)
{
- static GLuint displist1 = 0;
- static GLuint displist2 = 0;
-
- /* initialize 2 display lists for diamond shape - one empty, one filled */
- if (displist1 == 0) {
- displist1 = glGenLists(1);
- glNewList(displist1, GL_COMPILE);
-
- glBegin(GL_LINE_LOOP);
- glVertex2fv(_unit_diamond_shape[0]);
- glVertex2fv(_unit_diamond_shape[1]);
- glVertex2fv(_unit_diamond_shape[2]);
- glVertex2fv(_unit_diamond_shape[3]);
- glEnd();
-
- glEndList();
- }
- if (displist2 == 0) {
- displist2 = glGenLists(1);
- glNewList(displist2, GL_COMPILE);
-
- glBegin(GL_QUADS);
- glVertex2fv(_unit_diamond_shape[0]);
- glVertex2fv(_unit_diamond_shape[1]);
- glVertex2fv(_unit_diamond_shape[2]);
- glVertex2fv(_unit_diamond_shape[3]);
- glEnd();
-
- glEndList();
- }
+ bool draw_fill = ELEM(mode, KEYFRAME_SHAPE_INSIDE, KEYFRAME_SHAPE_BOTH);
+ bool draw_outline = ELEM(mode, KEYFRAME_SHAPE_FRAME, KEYFRAME_SHAPE_BOTH);
+
+ BLI_assert(draw_fill || draw_outline);
/* tweak size of keyframe shape according to type of keyframe
* - 'proper' keyframes have key_type = 0, so get drawn at full size
@@ -513,317 +554,349 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
break;
case BEZT_KEYTYPE_BREAKDOWN: /* slightly smaller than normal keyframe */
- hsize *= 0.85f;
+ size *= 0.85f;
break;
case BEZT_KEYTYPE_MOVEHOLD: /* slightly smaller than normal keyframes (but by less than for breakdowns) */
- //hsize *= 0.72f;
- hsize *= 0.95f;
+ size *= 0.925f;
break;
case BEZT_KEYTYPE_EXTREME: /* slightly larger */
- hsize *= 1.2f;
+ size *= 1.2f;
break;
default:
- hsize -= 0.5f * key_type;
- break;
+ size -= 0.8f * key_type;
}
- /* adjust view transform before starting */
- glTranslatef(x, y, 0.0f);
- glScalef(1.0f / xscale * hsize, hsize, 1.0f);
-
- /* anti-aliased lines for more consistent appearance */
- glEnable(GL_LINE_SMOOTH);
+ unsigned char fill_col[4];
+ unsigned char outline_col[4];
+ unsigned int flags = 0;
/* draw! */
- if (ELEM(mode, KEYFRAME_SHAPE_INSIDE, KEYFRAME_SHAPE_BOTH)) {
- float inner_col[4];
-
+ if (draw_fill) {
/* get interior colors from theme (for selected and unselected only) */
switch (key_type) {
case BEZT_KEYTYPE_BREAKDOWN: /* bluish frames (default theme) */
- {
- if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_BREAKDOWN_SELECT, inner_col);
- else UI_GetThemeColor4fv(TH_KEYTYPE_BREAKDOWN, inner_col);
+ UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_BREAKDOWN_SELECT : TH_KEYTYPE_BREAKDOWN, fill_col);
break;
- }
case BEZT_KEYTYPE_EXTREME: /* reddish frames (default theme) */
- {
- if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_EXTREME_SELECT, inner_col);
- else UI_GetThemeColor4fv(TH_KEYTYPE_EXTREME, inner_col);
+ UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_EXTREME_SELECT : TH_KEYTYPE_EXTREME, fill_col);
break;
- }
case BEZT_KEYTYPE_JITTER: /* greenish frames (default theme) */
- {
- if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_JITTER_SELECT, inner_col);
- else UI_GetThemeColor4fv(TH_KEYTYPE_JITTER, inner_col);
+ UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_JITTER_SELECT : TH_KEYTYPE_JITTER, fill_col);
break;
- }
case BEZT_KEYTYPE_MOVEHOLD: /* similar to traditional keyframes, but different... */
- {
- /* XXX: Should these get their own theme options instead? */
- if (sel) UI_GetThemeColorShade4fv(TH_STRIP_SELECT, 35, inner_col);
- else UI_GetThemeColorShade4fv(TH_STRIP, 50, inner_col);
-
- inner_col[3] = 1.0f; /* full opacity, to avoid problems with visual glitches */
+ UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_MOVEHOLD_SELECT : TH_KEYTYPE_MOVEHOLD, fill_col);
break;
- }
case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames (default theme) */
default:
- {
- if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_KEYFRAME_SELECT, inner_col);
- else UI_GetThemeColor4fv(TH_KEYTYPE_KEYFRAME, inner_col);
- break;
- }
+ UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_KEYFRAME_SELECT : TH_KEYTYPE_KEYFRAME, fill_col);
}
/* NOTE: we don't use the straight alpha from the theme, or else effects such as
* graying out protected/muted channels doesn't work correctly!
*/
- inner_col[3] *= alpha;
- glColor4fv(inner_col);
-
- /* draw the "filled in" interior poly now */
- glCallList(displist2);
+ fill_col[3] *= alpha;
+
+ if (!draw_outline) {
+ /* force outline color to match */
+ outline_col[0] = fill_col[0];
+ outline_col[1] = fill_col[1];
+ outline_col[2] = fill_col[2];
+ outline_col[3] = fill_col[3];
+ }
}
- if (ELEM(mode, KEYFRAME_SHAPE_FRAME, KEYFRAME_SHAPE_BOTH)) {
- float border_col[4];
-
+ if (draw_outline) {
/* exterior - black frame */
- if (sel) UI_GetThemeColor4fv(TH_KEYBORDER_SELECT, border_col);
- else UI_GetThemeColor4fv(TH_KEYBORDER, border_col);
+ UI_GetThemeColor4ubv(sel ? TH_KEYBORDER_SELECT : TH_KEYBORDER, outline_col);
+ outline_col[3] *= alpha;
+
+ if (!draw_fill) {
+ /* fill color needs to be (outline.rgb, 0) */
+ fill_col[0] = outline_col[0];
+ fill_col[1] = outline_col[1];
+ fill_col[2] = outline_col[2];
+ fill_col[3] = 0;
+ }
- border_col[3] *= alpha;
- glColor4fv(border_col);
+ /* 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 */
- glCallList(displist1);
- }
+ case KEYFRAME_HANDLE_FREE:
+ default:
+ flags = 1; /* diamond */
+ }
- glDisable(GL_LINE_SMOOTH);
+ /* 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;
+ }
+ }
- /* restore view transform */
- glScalef(xscale / hsize, 1.0f / hsize, 1.0f);
- glTranslatef(-x, -y, 0.0f);
+ 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, DLRBT_Tree *blocks, 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)
{
- ActKeyColumn *ak;
- ActKeyBlock *ab;
- float alpha;
- float xscale;
-
- const float iconsize = (U.widget_unit / 4.0f) * yscale_fac;
- const float mhsize = iconsize * 0.7f;
+ 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;
- glEnable(GL_BLEND);
-
- /* get View2D scaling factor */
- UI_view2d_scale_get(v2d, &xscale, NULL);
+ GPU_blend(true);
/* locked channels are less strongly shown, as feedback for locked channels in DopeSheet */
/* TODO: allow this opacity factor to be themed? */
- alpha = (channelLocked) ? 0.25f : 1.0f;
+ float alpha = channelLocked ? 0.25f : 1.0f;
+
+ /* Show interpolation and handle type? */
+ bool show_ipo = (saction_flag & SACTION_SHOW_INTERPOLATION) != 0;
/* draw keyblocks */
- if (blocks) {
+ 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;
- /* NOTE: the tradeoff for changing colors between each draw is dwarfed by the cost of checking validity */
- for (ab = blocks->first; ab; ab = ab->next) {
- if (actkeyblock_is_valid(ab, keys)) {
- if (ab->flag & ACTKEYBLOCK_FLAG_MOVING_HOLD) {
- /* draw "moving hold" long-keyframe block - slightly smaller */
- if (ab->sel)
- glColor4fv(sel_mhcol);
- else
- glColor4fv(unsel_mhcol);
-
- glRectf(ab->start, ypos - mhsize, ab->end, ypos + mhsize);
+ 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) {
+ GPUVertFormat *format = immVertexFormat();
+ uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+
+ immBegin(GPU_PRIM_TRIS, 6 * block_len);
+ for (ActKeyColumn *ab = keys->first; ab; ab = ab->next) {
+ int valid_hold = actkeyblock_get_valid_hold(ab);
+ if (valid_hold != 0) {
+ if ((valid_hold & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
+ /* draw "moving hold" long-keyframe block - slightly smaller */
+ immRectf_fast_with_color(pos_id, color_id,
+ ab->cfra, ypos - smaller_sz, ab->next->cfra, ypos + smaller_sz,
+ (ab->block.sel) ? sel_mhcol : unsel_mhcol);
+ }
+ else {
+ /* draw standard long-keyframe block */
+ immRectf_fast_with_color(pos_id, color_id,
+ ab->cfra, ypos - half_icon_sz, ab->next->cfra, ypos + half_icon_sz,
+ (ab->block.sel) ? sel_color : unsel_color);
+ }
}
- else {
- /* draw standard long-keyframe block */
- if (ab->sel)
- glColor4fv(sel_color);
- else
- glColor4fv(unsel_color);
-
- glRectf(ab->start, ypos - iconsize, ab->end, ypos + iconsize);
+ 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();
}
}
- /* draw keys */
if (keys) {
- for (ak = keys->first; ak; ak = ak->next) {
+ /* count keys */
+ uint key_len = 0;
+ for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) {
/* optimization: if keyframe doesn't appear within 5 units (screenspace) in visible area, don't draw
* - this might give some improvements, since we current have to flip between view/region matrices
*/
- if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax) == 0)
- continue;
+ if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax))
+ key_len++;
+ }
- /* draw using OpenGL - uglier but faster */
- /* NOTE1: a previous version of this didn't work nice for some intel cards
- * NOTE2: if we wanted to go back to icons, these are icon = (ak->sel & SELECT) ? ICON_SPACE2 : ICON_SPACE3; */
- draw_keyframe_shape(ak->cfra, ypos, xscale, iconsize, (ak->sel & SELECT), ak->key_type, KEYFRAME_SHAPE_BOTH, alpha);
+ if (key_len > 0) {
+ /* draw keys */
+ 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", 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, flags_id, handle_type, extreme_type);
+ }
+ }
+
+ immEnd();
+ GPU_disable_program_point_size();
+ immUnbindProgram();
}
}
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
/* *************************** 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, blocks;
+ DLRBT_Tree keys;
- BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_init(&blocks);
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
- summary_to_keylist(ac, &keys, &blocks);
+ BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_linkedlist_sync(&keys);
- BLI_dlrbTree_linkedlist_sync(&blocks);
+ summary_to_keylist(ac, &keys, saction_flag);
- draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
BLI_dlrbTree_free(&keys);
- BLI_dlrbTree_free(&blocks);
}
-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, blocks;
+ DLRBT_Tree keys;
- BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_init(&blocks);
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
- scene_to_keylist(ads, sce, &keys, &blocks);
+ BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_linkedlist_sync(&keys);
- BLI_dlrbTree_linkedlist_sync(&blocks);
+ scene_to_keylist(ads, sce, &keys, saction_flag);
- draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
BLI_dlrbTree_free(&keys);
- BLI_dlrbTree_free(&blocks);
}
-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, blocks;
+ DLRBT_Tree keys;
- BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_init(&blocks);
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
- ob_to_keylist(ads, ob, &keys, &blocks);
+ BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_linkedlist_sync(&keys);
- BLI_dlrbTree_linkedlist_sync(&blocks);
+ ob_to_keylist(ads, ob, &keys, saction_flag);
- draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
BLI_dlrbTree_free(&keys);
- BLI_dlrbTree_free(&blocks);
}
-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, blocks;
+ DLRBT_Tree keys;
bool locked = (fcu->flag & FCURVE_PROTECTED) ||
((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ||
((adt && adt->action) && ID_IS_LINKED(adt->action));
BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_init(&blocks);
-
- fcurve_to_keylist(adt, fcu, &keys, &blocks);
- BLI_dlrbTree_linkedlist_sync(&keys);
- BLI_dlrbTree_linkedlist_sync(&blocks);
+ fcurve_to_keylist(adt, fcu, &keys, saction_flag);
- draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
BLI_dlrbTree_free(&keys);
- BLI_dlrbTree_free(&blocks);
}
-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, blocks;
+ DLRBT_Tree keys;
bool locked = (agrp->flag & AGRP_PROTECTED) ||
((adt && adt->action) && ID_IS_LINKED(adt->action));
BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_init(&blocks);
-
- agroup_to_keylist(adt, agrp, &keys, &blocks);
- BLI_dlrbTree_linkedlist_sync(&keys);
- BLI_dlrbTree_linkedlist_sync(&blocks);
+ agroup_to_keylist(adt, agrp, &keys, saction_flag);
- draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
BLI_dlrbTree_free(&keys);
- BLI_dlrbTree_free(&blocks);
}
-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, blocks;
+ DLRBT_Tree keys;
bool locked = (act && ID_IS_LINKED(act));
- BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_init(&blocks);
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
- action_to_keylist(adt, act, &keys, &blocks);
+ BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_linkedlist_sync(&keys);
- BLI_dlrbTree_linkedlist_sync(&blocks);
+ action_to_keylist(adt, act, &keys, saction_flag);
- draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
BLI_dlrbTree_free(&keys);
- BLI_dlrbTree_free(&blocks);
}
-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;
- BLI_dlrbTree_init(&keys);
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
- gpencil_to_keylist(ads, gpd, &keys);
+ BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_linkedlist_sync(&keys);
+ gpencil_to_keylist(ads, gpd, &keys, false);
- draw_keylist(v2d, &keys, NULL, 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;
@@ -833,14 +906,12 @@ void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos,
gpl_to_keylist(ads, gpl, &keys);
- BLI_dlrbTree_linkedlist_sync(&keys);
-
- draw_keylist(v2d, &keys, NULL, 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;
@@ -850,16 +921,14 @@ void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, floa
mask_to_keylist(ads, masklay, &keys);
- BLI_dlrbTree_linkedlist_sync(&keys);
-
- draw_keylist(v2d, &keys, NULL, 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, DLRBT_Tree *blocks)
+void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, int saction_flag)
{
if (ac) {
ListBase anim_data = {NULL, NULL};
@@ -879,7 +948,7 @@ void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, DLRBT_Tree *blocks)
switch (ale->datatype) {
case ALE_FCURVE:
- fcurve_to_keylist(ale->adt, ale->data, keys, blocks);
+ fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
break;
case ALE_MASKLAY:
mask_to_keylist(ac->ads, ale->data, keys);
@@ -897,7 +966,7 @@ void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, DLRBT_Tree *blocks)
}
}
-void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, DLRBT_Tree *blocks)
+void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, int saction_flag)
{
bAnimContext ac = {NULL};
ListBase anim_data = {NULL, NULL};
@@ -925,12 +994,12 @@ void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, DLRBT_Tree
/* 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, blocks);
+ 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, DLRBT_Tree *blocks)
+void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, int saction_flag)
{
bAnimContext ac = {NULL};
ListBase anim_data = {NULL, NULL};
@@ -961,12 +1030,12 @@ void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, DLRBT_Tree *bl
/* 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, blocks);
+ 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, DLRBT_Tree *blocks)
+void cachefile_to_keylist(bDopeSheet *ads, CacheFile *cache_file, DLRBT_Tree *keys, int saction_flag)
{
if (cache_file == NULL) {
return;
@@ -991,33 +1060,40 @@ 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, blocks);
+ 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, DLRBT_Tree *blocks)
+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);
- /* loop through beztriples, making ActKeysColumns and ActKeyBlocks */
- for (v = 0, bezt = fcu->bezt; v < fcu->totvert; v++, bezt++) {
- add_bezt_to_keycolumns_list(keys, bezt);
- if (blocks) add_bezt_to_keyblocks_list(blocks, fcu->bezt, bezt);
+ /* Check if the curve is cyclic. */
+ bool is_cyclic = BKE_fcurve_is_cyclic(fcu) && (fcu->totvert >= 2);
+ bool do_extremes = (saction_flag & SACTION_SHOW_EXTREMES) != 0;
+
+ /* loop through beztriples, making ActKeysColumns */
+ BezTripleChain chain = { 0 };
+
+ for (int v = 0; v < fcu->totvert; v++) {
+ chain.cur = &fcu->bezt[v];
+
+ /* Neighbor keys, accounting for being cyclic. */
+ if (do_extremes) {
+ chain.prev = (v > 0) ? &fcu->bezt[v - 1] : is_cyclic ? &fcu->bezt[fcu->totvert - 2] : NULL;
+ chain.next = (v + 1 < fcu->totvert) ? &fcu->bezt[v + 1] : is_cyclic ? &fcu->bezt[1] : NULL;
+ }
+
+ add_bezt_to_keycolumns_list(keys, &chain);
}
- /* update the number of curves that elements have appeared in */
- if (keys)
- set_touched_actkeycolumn(keys->root);
- if (blocks)
- set_touched_actkeyblock(blocks->root);
+ /* Update keyblocks. */
+ update_keyblocks(keys, fcu->bezt, fcu->totvert);
/* unapply NLA-mapping if applicable */
if (adt)
@@ -1025,40 +1101,42 @@ void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, DLRBT_Tree
}
}
-void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, DLRBT_Tree *keys, DLRBT_Tree *blocks)
+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, blocks);
+ fcurve_to_keylist(adt, fcu, keys, saction_flag);
}
}
}
-void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, DLRBT_Tree *blocks)
+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, blocks);
+ fcurve_to_keylist(adt, fcu, keys, saction_flag);
}
}
}
-void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys)
+void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys, const bool active)
{
bGPDlayer *gpl;
if (gpd && keys) {
/* for now, just aggregate out all the frames, but only for visible layers */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) {
if ((gpl->flag & GP_LAYER_HIDE) == 0) {
- gpl_to_keylist(ads, gpl, keys);
+ if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) {
+ gpl_to_keylist(ads, gpl, keys);
+ }
}
}
}
@@ -1072,6 +1150,8 @@ void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys)
/* although the frames should already be in an ordered list, they are not suitable for displaying yet */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next)
add_gpframe_to_keycolumns_list(keys, gpf);
+
+ update_keyblocks(keys, NULL, 0);
}
}
@@ -1086,5 +1166,7 @@ void mask_to_keylist(bDopeSheet *UNUSED(ads), MaskLayer *masklay, DLRBT_Tree *ke
{
add_masklay_to_keycolumns_list(keys, masklay_shape);
}
+
+ update_keyblocks(keys, NULL, 0);
}
}
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index c8b0ed391f9..e733bb0f8b7 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -416,16 +416,14 @@ void ANIM_editkeyframes_refresh(bAnimContext *ac)
filter = ANIMFILTER_DATA_VISIBLE;
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- /* loop over F-Curves that are likely to have been edited, and check them */
+ /* Loop over F-Curves that are likely to have been edited, and tag them to
+ * ensure the keyframes are in order and handles are in a valid position. */
for (ale = anim_data.first; ale; ale = ale->next) {
- FCurve *fcu = ale->key_data;
-
- /* make sure keyframes in F-Curve are all in order, and handles are in valid positions */
- sort_time_fcurve(fcu);
- calchandles_fcurve(fcu);
+ ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES | ANIM_UPDATE_ORDER;
}
/* free temp data */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index aad9835f2aa..df87e1b7a5f 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -47,7 +47,6 @@
#include "BKE_action.h"
#include "BKE_fcurve.h"
#include "BKE_report.h"
-#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_global.h"
#include "BKE_deform.h"
@@ -183,7 +182,8 @@ void duplicate_fcurve_keys(FCurve *fcu)
/* Various Tools */
/* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only
- * optionally clears up curve if one keyframe with default value remains */
+ * optionally clears up curve if one keyframe with default value remains
+ */
void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault)
{
FCurve *fcu = (FCurve *)ale->key_data;
@@ -206,7 +206,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
/* now insert first keyframe, as it should be ok */
bezt = old_bezts;
- insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], BEZKEYTYPE(bezt), 0);
+ insert_bezt_fcurve(fcu, bezt, 0);
if (!(bezt->f2 & SELECT)) {
lastb = fcu->bezt;
lastb->f1 = lastb->f2 = lastb->f3 = 0;
@@ -235,7 +235,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
if (!(bezt->f2 & SELECT)) {
- insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
+ insert_bezt_fcurve(fcu, bezt, 0);
lastb = (fcu->bezt + (fcu->totvert - 1));
lastb->f1 = lastb->f2 = lastb->f3 = 0;
continue;
@@ -254,7 +254,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
if (cur[1] > next[1]) {
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
+ insert_bezt_fcurve(fcu, bezt, 0);
}
}
}
@@ -262,7 +262,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
/* only add if values are a considerable distance apart */
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
+ insert_bezt_fcurve(fcu, bezt, 0);
}
}
}
@@ -271,19 +271,19 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
if (beztn) {
/* does current have same value as previous and next? */
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
- /* add new keyframe*/
- insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
+ /* add new keyframe */
+ insert_bezt_fcurve(fcu, bezt, 0);
}
else if (IS_EQT(cur[1], next[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
+ insert_bezt_fcurve(fcu, bezt, 0);
}
}
else {
/* add if value doesn't equal that of previous */
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
+ insert_bezt_fcurve(fcu, bezt, 0);
}
}
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 9ea43c160a6..4bf6c43e348 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -57,7 +57,6 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idcode.h"
@@ -67,6 +66,10 @@
#include "BKE_nla.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
#include "ED_anim_api.h"
#include "ED_keyframing.h"
#include "ED_keyframes_edit.h"
@@ -113,6 +116,10 @@ short ANIM_get_keyframing_flags(Scene *scene, short incl_mode)
/* keyframing mode - only replace existing keyframes */
if (IS_AUTOKEY_MODE(scene, EDITKEYS))
flag |= INSERTKEY_REPLACE;
+
+ /* cycle-aware keyframe insertion - preserve cycle period and flow */
+ if (IS_AUTOKEY_FLAG(scene, CYCLEAWARE))
+ flag |= INSERTKEY_CYCLE_AWARE;
}
return flag;
@@ -154,11 +161,12 @@ bAction *verify_adt_action(Main *bmain, ID *id, short add)
*/
adt->action->idroot = GS(id->name);
- /* tag depsgraph to be rebuilt to include time dependency */
- /* XXX: we probably should have bmain passed down, but that involves altering too many API's */
- DAG_relations_tag_update(bmain);
+ /* Tag depsgraph to be rebuilt to include time dependency. */
+ DEG_relations_tag_update(bmain);
}
+ DEG_id_tag_update(&adt->action->id, DEG_TAG_COPY_ON_WRITE);
+
/* return the action */
return adt->action;
}
@@ -166,7 +174,7 @@ bAction *verify_adt_action(Main *bmain, ID *id, short add)
/* Get (or add relevant data to be able to do so) F-Curve from the Active Action,
* for the given Animation Data block. This assumes that all the destinations are valid.
*/
-FCurve *verify_fcurve(bAction *act, const char group[], PointerRNA *ptr,
+FCurve *verify_fcurve(Main *bmain, bAction *act, const char group[], PointerRNA *ptr,
const char rna_path[], const int array_index, short add)
{
bActionGroup *agrp;
@@ -227,6 +235,11 @@ FCurve *verify_fcurve(bAction *act, const char group[], PointerRNA *ptr,
/* just add F-Curve to end of Action's list */
BLI_addtail(&act->curves, fcu);
}
+
+ /* New f-curve was added, meaning it's possible that it affects
+ * dependency graph component which wasn't previously animated.
+ */
+ DEG_relations_tag_update(bmain);
}
/* return the F-Curve */
@@ -294,8 +307,67 @@ void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, Poin
/* ************************************************** */
/* KEYFRAME INSERTION */
+/* Move the point where a key is about to be inserted to be inside the main cycle range.
+ * Returns the type of the cycle if it is enabled and valid.
+ */
+static eFCU_Cycle_Type remap_cyclic_keyframe_location(FCurve *fcu, float *px, float *py)
+{
+ if (fcu->totvert < 2 || !fcu->bezt) {
+ return FCU_CYCLE_NONE;
+ }
+
+ eFCU_Cycle_Type type = BKE_fcurve_get_cycle_type(fcu);
+
+ if (type == FCU_CYCLE_NONE) {
+ return FCU_CYCLE_NONE;
+ }
+
+ BezTriple *first = &fcu->bezt[0], *last = &fcu->bezt[fcu->totvert - 1];
+ float start = first->vec[1][0], end = last->vec[1][0];
+
+ if (start >= end) {
+ return FCU_CYCLE_NONE;
+ }
+
+ if (*px < start || *px > end) {
+ float period = end - start;
+ float step = floorf((*px - start) / period);
+ *px -= step * period;
+
+ if (type == FCU_CYCLE_OFFSET) {
+ /* Nasty check to handle the case when the modes are different better. */
+ FMod_Cycles *data = ((FModifier *)fcu->modifiers.first)->data;
+ short mode = (step >= 0) ? data->after_mode : data->before_mode;
+
+ if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
+ *py -= step * (last->vec[1][1] - first->vec[1][1]);
+ }
+ }
+ }
+
+ return type;
+}
+
/* -------------- BezTriple Insertion -------------------- */
+/* Change the Y position of a keyframe to match the input, adjusting handles. */
+static void replace_bezt_keyframe_ypos(BezTriple *dst, const BezTriple *bezt)
+{
+ /* just change the values when replacing, so as to not overwrite handles */
+ float dy = bezt->vec[1][1] - dst->vec[1][1];
+
+ /* just apply delta value change to the handle values */
+ dst->vec[0][1] += dy;
+ dst->vec[1][1] += dy;
+ dst->vec[2][1] += dy;
+
+ dst->f1 = bezt->f1;
+ dst->f2 = bezt->f2;
+ dst->f3 = bezt->f3;
+
+ /* TODO: perform some other operations? */
+}
+
/* This function adds a given BezTriple to an F-Curve. It will allocate
* memory for the array if needed, and will insert the BezTriple into a
* suitable place in chronological order.
@@ -320,20 +392,14 @@ int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
fcu->bezt[i] = *bezt;
}
else {
- /* just change the values when replacing, so as to not overwrite handles */
- BezTriple *dst = (fcu->bezt + i);
- float dy = bezt->vec[1][1] - dst->vec[1][1];
-
- /* just apply delta value change to the handle values */
- dst->vec[0][1] += dy;
- dst->vec[1][1] += dy;
- dst->vec[2][1] += dy;
-
- dst->f1 = bezt->f1;
- dst->f2 = bezt->f2;
- dst->f3 = bezt->f3;
+ replace_bezt_keyframe_ypos(&fcu->bezt[i], bezt);
+ }
- /* TODO: perform some other operations? */
+ if (flag & INSERTKEY_CYCLE_AWARE) {
+ /* If replacing an end point of a cyclic curve without offset, modify the other end too. */
+ if ((i == 0 || i == fcu->totvert - 1) && BKE_fcurve_get_cycle_type(fcu) == FCU_CYCLE_PERFECT) {
+ replace_bezt_keyframe_ypos(&fcu->bezt[i == 0 ? fcu->totvert - 1 : 0], bezt);
+ }
}
}
}
@@ -612,31 +678,36 @@ static short new_key_needed(FCurve *fcu, float cFrame, float nValue)
/* ------------------ RNA Data-Access Functions ------------------ */
/* Try to read value using RNA-properties obtained already */
-static float setting_get_rna_value(PointerRNA *ptr, PropertyRNA *prop, int index)
+static float setting_get_rna_value(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, int index, const bool get_evaluated)
{
+ PointerRNA ptr_eval = *ptr;
float value = 0.0f;
+ if (get_evaluated) {
+ DEG_get_evaluated_rna_pointer(depsgraph, ptr, &ptr_eval);
+ }
+
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
if (RNA_property_array_check(prop))
- value = (float)RNA_property_boolean_get_index(ptr, prop, index);
+ value = (float)RNA_property_boolean_get_index(&ptr_eval, prop, index);
else
- value = (float)RNA_property_boolean_get(ptr, prop);
+ value = (float)RNA_property_boolean_get(&ptr_eval, prop);
break;
case PROP_INT:
if (RNA_property_array_check(prop))
- value = (float)RNA_property_int_get_index(ptr, prop, index);
+ value = (float)RNA_property_int_get_index(&ptr_eval, prop, index);
else
- value = (float)RNA_property_int_get(ptr, prop);
+ value = (float)RNA_property_int_get(&ptr_eval, prop);
break;
case PROP_FLOAT:
if (RNA_property_array_check(prop))
- value = RNA_property_float_get_index(ptr, prop, index);
+ value = RNA_property_float_get_index(&ptr_eval, prop, index);
else
- value = RNA_property_float_get(ptr, prop);
+ value = RNA_property_float_get(&ptr_eval, prop);
break;
case PROP_ENUM:
- value = (float)RNA_property_enum_get(ptr, prop);
+ value = (float)RNA_property_enum_get(&ptr_eval, prop);
break;
default:
break;
@@ -739,6 +810,7 @@ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
switch (con->type) {
/* multi-transform constraints */
case CONSTRAINT_TYPE_CHILDOF:
+ case CONSTRAINT_TYPE_ARMATURE:
return true;
case CONSTRAINT_TYPE_TRANSFORM:
case CONSTRAINT_TYPE_TRANSLIKE:
@@ -797,7 +869,7 @@ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
* In the event that it is not possible to perform visual keying, try to fall-back
* to using the default method. Assumes that all data it has been passed is valid.
*/
-static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_index)
+static float visualkey_get_value(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, int array_index)
{
const char *identifier = RNA_property_identifier(prop);
float tmat[4][4];
@@ -812,20 +884,25 @@ static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_i
*/
if (ptr->type == &RNA_Object) {
Object *ob = (Object *)ptr->data;
+ const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
/* Loc code is specific... */
if (strstr(identifier, "location")) {
- return ob->obmat[3][array_index];
+ return ob_eval->obmat[3][array_index];
}
- copy_m4_m4(tmat, ob->obmat);
- rotmode = ob->rotmode;
+ copy_m4_m4(tmat, ob_eval->obmat);
+ rotmode = ob_eval->rotmode;
}
else if (ptr->type == &RNA_PoseBone) {
+ Object *ob = (Object *)ptr->id.data;
bPoseChannel *pchan = (bPoseChannel *)ptr->data;
- BKE_armature_mat_pose_to_bone(pchan, pchan->pose_mat, tmat);
- rotmode = pchan->rotmode;
+ const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
+
+ BKE_armature_mat_pose_to_bone(pchan_eval, pchan_eval->pose_mat, tmat);
+ rotmode = pchan_eval->rotmode;
/* Loc code is specific... */
if (strstr(identifier, "location")) {
@@ -835,7 +912,7 @@ static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_i
}
}
else {
- return setting_get_rna_value(ptr, prop, array_index);
+ return setting_get_rna_value(depsgraph, ptr, prop, array_index, true);
}
/* Rot/Scale code are common! */
@@ -873,7 +950,7 @@ static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_i
}
/* as the function hasn't returned yet, read value from system in the default way */
- return setting_get_rna_value(ptr, prop, array_index);
+ return setting_get_rna_value(depsgraph, ptr, prop, array_index, true);
}
/* ------------------------- Insert Key API ------------------------- */
@@ -888,7 +965,7 @@ static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_i
* the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
* and extra keyframe filtering.
*/
-bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag)
+bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag)
{
float curval = 0.0f;
@@ -939,7 +1016,7 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
if (RNA_path_resolved_create(&ptr, prop, fcu->array_index, &anim_rna)) {
/* for making it easier to add corrective drivers... */
- cfra = evaluate_driver(&anim_rna, fcu->driver, cfra);
+ cfra = evaluate_driver(&anim_rna, fcu->driver, fcu->driver, cfra);
}
else {
cfra = 0.0f;
@@ -954,11 +1031,19 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
* it works by keyframing using a value extracted from the final matrix
* instead of using the kt system to extract a value.
*/
- curval = visualkey_get_value(&ptr, prop, fcu->array_index);
+ curval = visualkey_get_value(depsgraph, &ptr, prop, fcu->array_index);
}
else {
/* read value from system */
- curval = setting_get_rna_value(&ptr, prop, fcu->array_index);
+ curval = setting_get_rna_value(depsgraph, &ptr, prop, fcu->array_index, false);
+ }
+
+ /* adjust coordinates for cycle aware insertion */
+ if (flag & INSERTKEY_CYCLE_AWARE) {
+ if (remap_cyclic_keyframe_location(fcu, &cfra, &curval) != FCU_CYCLE_PERFECT) {
+ /* inhibit action from insert_vert_fcurve unless it's a perfect cycle */
+ flag &= ~INSERTKEY_CYCLE_AWARE;
+ }
}
/* only insert keyframes where they are needed */
@@ -1008,7 +1093,7 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
* index of -1 keys all array indices
*/
short insert_keyframe(
- Main *bmain, ReportList *reports, ID *id, bAction *act,
+ Main *bmain, Depsgraph *depsgraph, ReportList *reports, ID *id, bAction *act,
const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag)
{
PointerRNA id_ptr, ptr;
@@ -1068,7 +1153,7 @@ short insert_keyframe(
* - if we're replacing keyframes only, DO NOT create new F-Curves if they do not exist yet
* but still try to get the F-Curve if it exists...
*/
- fcu = verify_fcurve(act, group, &ptr, rna_path, array_index, (flag & INSERTKEY_REPLACE) == 0);
+ fcu = verify_fcurve(bmain, act, group, &ptr, rna_path, array_index, (flag & INSERTKEY_REPLACE) == 0);
/* we may not have a F-Curve when we're replacing only... */
if (fcu) {
@@ -1087,7 +1172,16 @@ short insert_keyframe(
}
/* insert keyframe */
- ret += insert_keyframe_direct(reports, ptr, prop, fcu, cfra, keytype, flag);
+ ret += insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, keytype, flag);
+ }
+ }
+
+ if (ret) {
+ if (act != NULL) {
+ DEG_id_tag_update(&act->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ if (adt != NULL && adt->action != NULL && adt->action != act) {
+ DEG_id_tag_update(&adt->action->id, DEG_TAG_COPY_ON_WRITE);
}
}
@@ -1132,7 +1226,9 @@ static bool delete_keyframe_fcurve(AnimData *adt, FCurve *fcu, float cfra)
return false;
}
-short delete_keyframe(ReportList *reports, ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, eInsertKeyFlags UNUSED(flag))
+short delete_keyframe(Main *bmain, ReportList *reports, ID *id, bAction *act,
+ const char group[], const char rna_path[], int array_index, float cfra,
+ eInsertKeyFlags UNUSED(flag))
{
AnimData *adt = BKE_animdata_from_id(id);
PointerRNA id_ptr, ptr;
@@ -1190,7 +1286,7 @@ short delete_keyframe(ReportList *reports, ID *id, bAction *act, const char grou
/* will only loop once unless the array index was -1 */
for (; array_index < array_index_max; array_index++) {
- FCurve *fcu = verify_fcurve(act, group, &ptr, rna_path, array_index, 0);
+ FCurve *fcu = verify_fcurve(bmain, act, group, &ptr, rna_path, array_index, 0);
/* check if F-Curve exists and/or whether it can be edited */
if (fcu == NULL)
@@ -1221,7 +1317,9 @@ short delete_keyframe(ReportList *reports, ID *id, bAction *act, const char grou
* The flag argument is used for special settings that alter the behavior of
* the keyframe deletion. These include the quick refresh options.
*/
-static short clear_keyframe(ReportList *reports, ID *id, bAction *act, const char group[], const char rna_path[], int array_index, eInsertKeyFlags UNUSED(flag))
+static short clear_keyframe(Main *bmain, ReportList *reports, ID *id, bAction *act,
+ const char group[], const char rna_path[], int array_index,
+ eInsertKeyFlags UNUSED(flag))
{
AnimData *adt = BKE_animdata_from_id(id);
PointerRNA id_ptr, ptr;
@@ -1276,7 +1374,7 @@ static short clear_keyframe(ReportList *reports, ID *id, bAction *act, const cha
/* will only loop once unless the array index was -1 */
for (; array_index < array_index_max; array_index++) {
- FCurve *fcu = verify_fcurve(act, group, &ptr, rna_path, array_index, 0);
+ FCurve *fcu = verify_fcurve(bmain, act, group, &ptr, rna_path, array_index, 0);
/* check if F-Curve exists and/or whether it can be edited */
if (fcu == NULL)
@@ -1621,7 +1719,7 @@ static int clear_anim_v3d_exec(bContext *C, wmOperator *UNUSED(op))
/* delete F-Curve completely */
if (can_delete) {
ANIM_fcurve_delete_from_animdata(NULL, adt, fcu);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
changed = true;
}
}
@@ -1728,7 +1826,7 @@ static int delete_key_v3d_exec(bContext *C, wmOperator *op)
else
BKE_reportf(op->reports, RPT_ERROR, "No keyframes removed from Object '%s'", id->name + 2);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
CTX_DATA_END;
@@ -1760,6 +1858,7 @@ void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot)
static int insert_key_button_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
@@ -1793,7 +1892,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
if (fcu) {
- success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0);
+ success = insert_keyframe_direct(depsgraph, op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0);
}
else {
BKE_report(op->reports, RPT_ERROR,
@@ -1808,7 +1907,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special);
if (fcu && driven) {
- success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER);
+ success = insert_keyframe_direct(depsgraph, op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER);
}
}
else {
@@ -1816,12 +1915,35 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
+ const char *identifier = RNA_property_identifier(prop);
+ const char *group = NULL;
+
+ /* Special exception for keyframing transforms:
+ * Set "group" for this manually, instead of having them appearing at the bottom (ungrouped)
+ * part of the channels list. Leaving these ungrouped is not a nice user behaviour in this case.
+ *
+ * TODO: Perhaps we can extend this behaviour in future for other properties...
+ */
+ if (ptr.type == &RNA_PoseBone) {
+ bPoseChannel *pchan = (bPoseChannel *)ptr.data;
+ group = pchan->name;
+ }
+ else if ((ptr.type == &RNA_Object) &&
+ (strstr(identifier, "location") || strstr(identifier, "rotation") || strstr(identifier, "scale")))
+ {
+ /* NOTE: Keep this label in sync with the "ID" case in
+ * keyingsets_utils.py :: get_transform_generators_base_info()
+ */
+ group = "Object Transforms";
+ }
+
+
if (all) {
/* -1 indicates operating on the entire array (or the property itself otherwise) */
index = -1;
}
- success = insert_keyframe(bmain, op->reports, ptr.id.data, NULL, NULL, path, index, cfra, ts->keyframe_type, flag);
+ success = insert_keyframe(bmain, depsgraph, op->reports, ptr.id.data, NULL, group, path, index, cfra, ts->keyframe_type, flag);
MEM_freeN(path);
}
@@ -1881,6 +2003,7 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
PointerRNA ptr = {{NULL}};
PropertyRNA *prop = NULL;
+ Main *bmain = CTX_data_main(C);
char *path;
float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
short success = 0;
@@ -1937,7 +2060,7 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
index = -1;
}
- success = delete_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, cfra, 0);
+ success = delete_keyframe(bmain, op->reports, ptr.id.data, NULL, NULL, path, index, cfra, 0);
MEM_freeN(path);
}
else if (G.debug & G_DEBUG)
@@ -1985,6 +2108,7 @@ static int clear_key_button_exec(bContext *C, wmOperator *op)
{
PointerRNA ptr = {{NULL}};
PropertyRNA *prop = NULL;
+ Main *bmain = CTX_data_main(C);
char *path;
short success = 0;
int index;
@@ -2005,7 +2129,7 @@ static int clear_key_button_exec(bContext *C, wmOperator *op)
index = -1;
}
- success += clear_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, 0);
+ success += clear_keyframe(bmain, op->reports, ptr.id.data, NULL, NULL, path, index, 0);
MEM_freeN(path);
}
else if (G.debug & G_DEBUG)
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index e4aeef72755..d8e9c5a7790 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -48,9 +48,10 @@
#include "BKE_main.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "ED_keyframing.h"
#include "ED_screen.h"
@@ -923,7 +924,8 @@ short ANIM_validate_keyingset(bContext *C, ListBase *dsources, KeyingSet *ks)
/* Determine which keying flags apply based on the override flags */
static short keyingset_apply_keying_flags(const short base_flags, const short overrides, const short own_flags)
{
- short result = 0;
+ /* Pass through all flags by default (i.e. even not explicitly listed ones). */
+ short result = base_flags;
/* The logic for whether a keying flag applies is as follows:
* - If the flag in question is set in "overrides", that means that the
@@ -933,10 +935,8 @@ static short keyingset_apply_keying_flags(const short base_flags, const short ov
*/
#define APPLY_KEYINGFLAG_OVERRIDE(kflag) \
if (overrides & kflag) { \
+ result &= ~kflag; \
result |= (own_flags & kflag); \
- } \
- else { \
- result |= (base_flags & kflag); \
}
/* Apply the flags one by one...
@@ -957,6 +957,7 @@ static short keyingset_apply_keying_flags(const short base_flags, const short ov
*/
int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ReportList *reports = CTX_wm_reports(C);
@@ -1038,9 +1039,9 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
for (; i < arraylen; i++) {
/* action to take depends on mode */
if (mode == MODIFYKEY_MODE_INSERT)
- success += insert_keyframe(bmain, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, keytype, kflag2);
+ success += insert_keyframe(bmain, depsgraph, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, keytype, kflag2);
else if (mode == MODIFYKEY_MODE_DELETE)
- success += delete_keyframe(reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2);
+ success += delete_keyframe(bmain, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2);
}
/* set recalc-flags */
@@ -1050,10 +1051,11 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
Object *ob = (Object *)ksp->id;
// XXX: only object transforms?
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
break;
}
default:
+ DEG_id_tag_update(ksp->id, DEG_TAG_COPY_ON_WRITE);
break;
}