diff options
Diffstat (limited to 'source/blender/editors/animation')
-rw-r--r-- | source/blender/editors/animation/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_channels_defines.c | 191 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_channels_edit.c | 172 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_deps.c | 36 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_draw.c | 163 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_filter.c | 158 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_intern.h | 1 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_markers.c | 303 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_ops.c | 142 | ||||
-rw-r--r-- | source/blender/editors/animation/drivers.c | 148 | ||||
-rw-r--r-- | source/blender/editors/animation/keyframes_draw.c | 960 | ||||
-rw-r--r-- | source/blender/editors/animation/keyframes_edit.c | 10 | ||||
-rw-r--r-- | source/blender/editors/animation/keyframes_general.c | 20 | ||||
-rw-r--r-- | source/blender/editors/animation/keyframing.c | 228 | ||||
-rw-r--r-- | source/blender/editors/animation/keyingsets.c | 18 |
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; } |