diff options
Diffstat (limited to 'source/blender/editors/animation/keyframing.c')
-rw-r--r-- | source/blender/editors/animation/keyframing.c | 4648 |
1 files changed, 2442 insertions, 2206 deletions
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 793a73e6939..cc8dbbca439 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -21,7 +21,6 @@ * \ingroup edanimation */ - #include <stdio.h> #include <stddef.h> #include <string.h> @@ -80,7 +79,9 @@ #include "anim_intern.h" -static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op, PropertyRNA *prop, Scene *scene); +static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op, + PropertyRNA *prop, + Scene *scene); /* ************************************************** */ /* Keyframing Setting Wrangling */ @@ -88,35 +89,35 @@ static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op, PropertyRNA * /* Get the active settings for keyframing settings from context (specifically the given scene) */ short ANIM_get_keyframing_flags(Scene *scene, short incl_mode) { - eInsertKeyFlags flag = INSERTKEY_NOFLAGS; - - /* standard flags */ - { - /* visual keying */ - if (IS_AUTOKEY_FLAG(scene, AUTOMATKEY)) - flag |= INSERTKEY_MATRIX; - - /* only needed */ - if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) - flag |= INSERTKEY_NEEDED; - - /* default F-Curve color mode - RGB from XYZ indices */ - if (IS_AUTOKEY_FLAG(scene, XYZ2RGB)) - flag |= INSERTKEY_XYZ2RGB; - } - - /* only if including settings from the autokeying mode... */ - if (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; + eInsertKeyFlags flag = INSERTKEY_NOFLAGS; + + /* standard flags */ + { + /* visual keying */ + if (IS_AUTOKEY_FLAG(scene, AUTOMATKEY)) + flag |= INSERTKEY_MATRIX; + + /* only needed */ + if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) + flag |= INSERTKEY_NEEDED; + + /* default F-Curve color mode - RGB from XYZ indices */ + if (IS_AUTOKEY_FLAG(scene, XYZ2RGB)) + flag |= INSERTKEY_XYZ2RGB; + } + + /* only if including settings from the autokeying mode... */ + if (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; } /* ******************************************* */ @@ -127,140 +128,145 @@ short ANIM_get_keyframing_flags(Scene *scene, short incl_mode) */ bAction *verify_adt_action(Main *bmain, ID *id, short add) { - AnimData *adt; - - /* init animdata if none available yet */ - adt = BKE_animdata_from_id(id); - if ((adt == NULL) && (add)) - adt = BKE_animdata_add_id(id); - if (adt == NULL) { - /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */ - printf("ERROR: Couldn't add AnimData (ID = %s)\n", (id) ? (id->name) : "<None>"); - return NULL; - } - - /* init action if none available yet */ - /* TODO: need some wizardry to handle NLA stuff correct */ - if ((adt->action == NULL) && (add)) { - /* init action name from name of ID block */ - char actname[sizeof(id->name) - 2]; - BLI_snprintf(actname, sizeof(actname), "%sAction", id->name + 2); - - /* create action */ - adt->action = BKE_action_add(bmain, actname); - - /* set ID-type from ID-block that this is going to be assigned to - * so that users can't accidentally break actions by assigning them - * to the wrong places - */ - adt->action->idroot = GS(id->name); - - /* Tag depsgraph to be rebuilt to include time dependency. */ - DEG_relations_tag_update(bmain); - } - - DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); - - /* return the action */ - return adt->action; + AnimData *adt; + + /* init animdata if none available yet */ + adt = BKE_animdata_from_id(id); + if ((adt == NULL) && (add)) + adt = BKE_animdata_add_id(id); + if (adt == NULL) { + /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */ + printf("ERROR: Couldn't add AnimData (ID = %s)\n", (id) ? (id->name) : "<None>"); + return NULL; + } + + /* init action if none available yet */ + /* TODO: need some wizardry to handle NLA stuff correct */ + if ((adt->action == NULL) && (add)) { + /* init action name from name of ID block */ + char actname[sizeof(id->name) - 2]; + BLI_snprintf(actname, sizeof(actname), "%sAction", id->name + 2); + + /* create action */ + adt->action = BKE_action_add(bmain, actname); + + /* set ID-type from ID-block that this is going to be assigned to + * so that users can't accidentally break actions by assigning them + * to the wrong places + */ + adt->action->idroot = GS(id->name); + + /* Tag depsgraph to be rebuilt to include time dependency. */ + DEG_relations_tag_update(bmain); + } + + DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); + + /* return the action */ + return adt->action; } /* 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(Main *bmain, bAction *act, const char group[], PointerRNA *ptr, - const char rna_path[], const int array_index, short add) +FCurve *verify_fcurve(Main *bmain, + bAction *act, + const char group[], + PointerRNA *ptr, + const char rna_path[], + const int array_index, + short add) { - bActionGroup *agrp; - FCurve *fcu; - - /* sanity checks */ - if (ELEM(NULL, act, rna_path)) - return NULL; - - /* try to find f-curve matching for this setting - * - add if not found and allowed to add one - * TODO: add auto-grouping support? how this works will need to be resolved - */ - fcu = list_find_fcurve(&act->curves, rna_path, array_index); - - if ((fcu == NULL) && (add)) { - /* use default settings to make a F-Curve */ - fcu = MEM_callocN(sizeof(FCurve), "FCurve"); - - fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; - if (BLI_listbase_is_empty(&act->curves)) - fcu->flag |= FCURVE_ACTIVE; /* first one added active */ - - /* store path - make copy, and store that */ - fcu->rna_path = BLI_strdup(rna_path); - fcu->array_index = array_index; - - /* if a group name has been provided, try to add or find a group, then add F-Curve to it */ - if (group) { - /* try to find group */ - agrp = BKE_action_group_find_name(act, group); - - /* no matching groups, so add one */ - if (agrp == NULL) { - agrp = action_groups_add_new(act, group); - - /* sync bone group colors if applicable */ - if (ptr && (ptr->type == &RNA_PoseBone)) { - Object *ob = (Object *)ptr->id.data; - bPoseChannel *pchan = (bPoseChannel *)ptr->data; - bPose *pose = ob->pose; - bActionGroup *grp; - - /* find bone group (if present), and use the color from that */ - grp = (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1)); - if (grp) { - agrp->customCol = grp->customCol; - action_group_colors_sync(agrp, grp); - } - } - } - - /* add F-Curve to group */ - action_groups_add_channel(act, agrp, fcu); - } - else { - /* 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 */ - return fcu; + bActionGroup *agrp; + FCurve *fcu; + + /* sanity checks */ + if (ELEM(NULL, act, rna_path)) + return NULL; + + /* try to find f-curve matching for this setting + * - add if not found and allowed to add one + * TODO: add auto-grouping support? how this works will need to be resolved + */ + fcu = list_find_fcurve(&act->curves, rna_path, array_index); + + if ((fcu == NULL) && (add)) { + /* use default settings to make a F-Curve */ + fcu = MEM_callocN(sizeof(FCurve), "FCurve"); + + fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); + fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + if (BLI_listbase_is_empty(&act->curves)) + fcu->flag |= FCURVE_ACTIVE; /* first one added active */ + + /* store path - make copy, and store that */ + fcu->rna_path = BLI_strdup(rna_path); + fcu->array_index = array_index; + + /* if a group name has been provided, try to add or find a group, then add F-Curve to it */ + if (group) { + /* try to find group */ + agrp = BKE_action_group_find_name(act, group); + + /* no matching groups, so add one */ + if (agrp == NULL) { + agrp = action_groups_add_new(act, group); + + /* sync bone group colors if applicable */ + if (ptr && (ptr->type == &RNA_PoseBone)) { + Object *ob = (Object *)ptr->id.data; + bPoseChannel *pchan = (bPoseChannel *)ptr->data; + bPose *pose = ob->pose; + bActionGroup *grp; + + /* find bone group (if present), and use the color from that */ + grp = (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1)); + if (grp) { + agrp->customCol = grp->customCol; + action_group_colors_sync(agrp, grp); + } + } + } + + /* add F-Curve to group */ + action_groups_add_channel(act, agrp, fcu); + } + else { + /* 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 */ + return fcu; } /* Helper for update_autoflags_fcurve() */ static void update_autoflags_fcurve_direct(FCurve *fcu, PropertyRNA *prop) { - /* set additional flags for the F-Curve (i.e. only integer values) */ - fcu->flag &= ~(FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES); - switch (RNA_property_type(prop)) { - case PROP_FLOAT: - /* do nothing */ - break; - case PROP_INT: - /* do integer (only 'whole' numbers) interpolation between all points */ - fcu->flag |= FCURVE_INT_VALUES; - break; - default: - /* do 'discrete' (i.e. enum, boolean values which cannot take any intermediate - * values at all) interpolation between all points - * - however, we must also ensure that evaluated values are only integers still - */ - fcu->flag |= (FCURVE_DISCRETE_VALUES | FCURVE_INT_VALUES); - break; - } + /* set additional flags for the F-Curve (i.e. only integer values) */ + fcu->flag &= ~(FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES); + switch (RNA_property_type(prop)) { + case PROP_FLOAT: + /* do nothing */ + break; + case PROP_INT: + /* do integer (only 'whole' numbers) interpolation between all points */ + fcu->flag |= FCURVE_INT_VALUES; + break; + default: + /* do 'discrete' (i.e. enum, boolean values which cannot take any intermediate + * values at all) interpolation between all points + * - however, we must also ensure that evaluated values are only integers still + */ + fcu->flag |= (FCURVE_DISCRETE_VALUES | FCURVE_INT_VALUES); + break; + } } /* Update integer/discrete flags of the FCurve (used when creating/inserting keyframes, @@ -268,34 +274,36 @@ static void update_autoflags_fcurve_direct(FCurve *fcu, PropertyRNA *prop) */ void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, PointerRNA *ptr) { - PointerRNA tmp_ptr; - PropertyRNA *prop; - int old_flag = fcu->flag; - - if ((ptr->id.data == NULL) && (ptr->data == NULL)) { - BKE_report(reports, RPT_ERROR, "No RNA pointer available to retrieve values for this fcurve"); - return; - } - - /* try to get property we should be affecting */ - if (RNA_path_resolve_property(ptr, fcu->rna_path, &tmp_ptr, &prop) == false) { - /* property not found... */ - const char *idname = (ptr->id.data) ? ((ID *)ptr->id.data)->name : TIP_("<No ID pointer>"); - - BKE_reportf(reports, RPT_ERROR, - "Could not update flags for this fcurve, as RNA path is invalid for the given ID " - "(ID = %s, path = %s)", - idname, fcu->rna_path); - return; - } - - /* update F-Curve flags */ - update_autoflags_fcurve_direct(fcu, prop); - - if (old_flag != fcu->flag) { - /* Same as if keyframes had been changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); - } + PointerRNA tmp_ptr; + PropertyRNA *prop; + int old_flag = fcu->flag; + + if ((ptr->id.data == NULL) && (ptr->data == NULL)) { + BKE_report(reports, RPT_ERROR, "No RNA pointer available to retrieve values for this fcurve"); + return; + } + + /* try to get property we should be affecting */ + if (RNA_path_resolve_property(ptr, fcu->rna_path, &tmp_ptr, &prop) == false) { + /* property not found... */ + const char *idname = (ptr->id.data) ? ((ID *)ptr->id.data)->name : TIP_("<No ID pointer>"); + + BKE_reportf(reports, + RPT_ERROR, + "Could not update flags for this fcurve, as RNA path is invalid for the given ID " + "(ID = %s, path = %s)", + idname, + fcu->rna_path); + return; + } + + /* update F-Curve flags */ + update_autoflags_fcurve_direct(fcu, prop); + + if (old_flag != fcu->flag) { + /* Same as if keyframes had been changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + } } /* ************************************************** */ @@ -306,40 +314,40 @@ void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, Poin */ static eFCU_Cycle_Type remap_cyclic_keyframe_location(FCurve *fcu, float *px, float *py) { - if (fcu->totvert < 2 || !fcu->bezt) { - return FCU_CYCLE_NONE; - } + if (fcu->totvert < 2 || !fcu->bezt) { + return FCU_CYCLE_NONE; + } - eFCU_Cycle_Type type = BKE_fcurve_get_cycle_type(fcu); + eFCU_Cycle_Type type = BKE_fcurve_get_cycle_type(fcu); - if (type == FCU_CYCLE_NONE) { - return FCU_CYCLE_NONE; - } + 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]; + 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 (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 (*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 (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]); - } - } - } + if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) { + *py -= step * (last->vec[1][1] - first->vec[1][1]); + } + } + } - return type; + return type; } /* -------------- BezTriple Insertion -------------------- */ @@ -347,19 +355,19 @@ static eFCU_Cycle_Type remap_cyclic_keyframe_location(FCurve *fcu, float *px, fl /* 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 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; + /* 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; + dst->f1 = bezt->f1; + dst->f2 = bezt->f2; + dst->f3 = bezt->f3; - /* TODO: perform some other operations? */ + /* TODO: perform some other operations? */ } /* This function adds a given BezTriple to an F-Curve. It will allocate @@ -371,81 +379,81 @@ static void replace_bezt_keyframe_ypos(BezTriple *dst, const BezTriple *bezt) */ int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag) { - int i = 0; - - /* are there already keyframes? */ - if (fcu->bezt) { - bool replace; - i = binarysearch_bezt_index(fcu->bezt, bezt->vec[1][0], fcu->totvert, &replace); - - /* replace an existing keyframe? */ - if (replace) { - /* sanity check: 'i' may in rare cases exceed arraylen */ - if ((i >= 0) && (i < fcu->totvert)) { - if (flag & INSERTKEY_OVERWRITE_FULL) { - fcu->bezt[i] = *bezt; - } - else { - replace_bezt_keyframe_ypos(&fcu->bezt[i], bezt); - } - - 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); - } - } - } - } - /* keyframing modes allow to not replace keyframe */ - else if ((flag & INSERTKEY_REPLACE) == 0) { - /* insert new - if we're not restricted to replacing keyframes only */ - BezTriple *newb = MEM_callocN((fcu->totvert + 1) * sizeof(BezTriple), "beztriple"); - - /* add the beztriples that should occur before the beztriple to be pasted (originally in fcu) */ - if (i > 0) - memcpy(newb, fcu->bezt, i * sizeof(BezTriple)); - - /* add beztriple to paste at index i */ - *(newb + i) = *bezt; - - /* add the beztriples that occur after the beztriple to be pasted (originally in fcu) */ - if (i < fcu->totvert) - memcpy(newb + i + 1, fcu->bezt + i, (fcu->totvert - i) * sizeof(BezTriple)); - - /* replace (+ free) old with new, only if necessary to do so */ - MEM_freeN(fcu->bezt); - fcu->bezt = newb; - - fcu->totvert++; - } - else { - return -1; - } - } - /* no keyframes already, but can only add if... - * 1) keyframing modes say that keyframes can only be replaced, so adding new ones won't know - * 2) there are no samples on the curve - * // NOTE: maybe we may want to allow this later when doing samples -> bezt conversions, - * // but for now, having both is asking for trouble - */ - else if ((flag & INSERTKEY_REPLACE) == 0 && (fcu->fpt == NULL)) { - /* create new keyframes array */ - fcu->bezt = MEM_callocN(sizeof(BezTriple), "beztriple"); - *(fcu->bezt) = *bezt; - fcu->totvert = 1; - } - /* cannot add anything */ - else { - /* return error code -1 to prevent any misunderstandings */ - return -1; - } - - - /* we need to return the index, so that some tools which do post-processing can - * detect where we added the BezTriple in the array - */ - return i; + int i = 0; + + /* are there already keyframes? */ + if (fcu->bezt) { + bool replace; + i = binarysearch_bezt_index(fcu->bezt, bezt->vec[1][0], fcu->totvert, &replace); + + /* replace an existing keyframe? */ + if (replace) { + /* sanity check: 'i' may in rare cases exceed arraylen */ + if ((i >= 0) && (i < fcu->totvert)) { + if (flag & INSERTKEY_OVERWRITE_FULL) { + fcu->bezt[i] = *bezt; + } + else { + replace_bezt_keyframe_ypos(&fcu->bezt[i], bezt); + } + + 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); + } + } + } + } + /* keyframing modes allow to not replace keyframe */ + else if ((flag & INSERTKEY_REPLACE) == 0) { + /* insert new - if we're not restricted to replacing keyframes only */ + BezTriple *newb = MEM_callocN((fcu->totvert + 1) * sizeof(BezTriple), "beztriple"); + + /* add the beztriples that should occur before the beztriple to be pasted (originally in fcu) */ + if (i > 0) + memcpy(newb, fcu->bezt, i * sizeof(BezTriple)); + + /* add beztriple to paste at index i */ + *(newb + i) = *bezt; + + /* add the beztriples that occur after the beztriple to be pasted (originally in fcu) */ + if (i < fcu->totvert) + memcpy(newb + i + 1, fcu->bezt + i, (fcu->totvert - i) * sizeof(BezTriple)); + + /* replace (+ free) old with new, only if necessary to do so */ + MEM_freeN(fcu->bezt); + fcu->bezt = newb; + + fcu->totvert++; + } + else { + return -1; + } + } + /* no keyframes already, but can only add if... + * 1) keyframing modes say that keyframes can only be replaced, so adding new ones won't know + * 2) there are no samples on the curve + * // NOTE: maybe we may want to allow this later when doing samples -> bezt conversions, + * // but for now, having both is asking for trouble + */ + else if ((flag & INSERTKEY_REPLACE) == 0 && (fcu->fpt == NULL)) { + /* create new keyframes array */ + fcu->bezt = MEM_callocN(sizeof(BezTriple), "beztriple"); + *(fcu->bezt) = *bezt; + fcu->totvert = 1; + } + /* cannot add anything */ + else { + /* return error code -1 to prevent any misunderstandings */ + return -1; + } + + /* we need to return the index, so that some tools which do post-processing can + * detect where we added the BezTriple in the array + */ + return i; } /** @@ -457,114 +465,116 @@ int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag) * \param flag: Optional flags (eInsertKeyFlags) for controlling how keys get added * and/or whether updates get done. */ -int insert_vert_fcurve(FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag) +int insert_vert_fcurve( + FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag) { - BezTriple beztr = {{{0}}}; - unsigned int oldTot = fcu->totvert; - int a; - - /* set all three points, for nicer start position - * NOTE: +/- 1 on vec.x for left and right handles is so that 'free' handles work ok... - */ - beztr.vec[0][0] = x - 1.0f; - beztr.vec[0][1] = y; - beztr.vec[1][0] = x; - beztr.vec[1][1] = y; - beztr.vec[2][0] = x + 1.0f; - beztr.vec[2][1] = y; - beztr.f1 = beztr.f2 = beztr.f3 = SELECT; - - /* set default handle types and interpolation mode */ - if (flag & INSERTKEY_NO_USERPREF) { - /* for Py-API, we want scripts to have predictable behavior, - * hence the option to not depend on the userpref defaults - */ - beztr.h1 = beztr.h2 = HD_AUTO_ANIM; - beztr.ipo = BEZT_IPO_BEZ; - } - else { - /* for UI usage - defaults should come from the userprefs and/or toolsettings */ - beztr.h1 = beztr.h2 = U.keyhandles_new; /* use default handle type here */ - - /* use default interpolation mode, with exceptions for int/discrete values */ - beztr.ipo = U.ipo_new; - } - - /* interpolation type used is constrained by the type of values the curve can take */ - if (fcu->flag & FCURVE_DISCRETE_VALUES) { - beztr.ipo = BEZT_IPO_CONST; - } - else if ((beztr.ipo == BEZT_IPO_BEZ) && (fcu->flag & FCURVE_INT_VALUES)) { - beztr.ipo = BEZT_IPO_LIN; - } - - /* set keyframe type value (supplied), which should come from the scene settings in most cases */ - BEZKEYTYPE(&beztr) = keyframe_type; - - /* set default values for "easing" interpolation mode settings - * NOTE: Even if these modes aren't currently used, if users switch - * to these later, we want these to work in a sane way out of - * the box. - */ - - /* "back" easing - this value used to be used when overshoot=0, but that - * introduced discontinuities in how the param worked. */ - beztr.back = 1.70158f; - - /* "elastic" easing - values here were hand-optimised for a default duration of - * ~10 frames (typical mograph motion length) */ - beztr.amplitude = 0.8f; - beztr.period = 4.1f; - - /* add temp beztriple to keyframes */ - a = insert_bezt_fcurve(fcu, &beztr, flag); - - /* what if 'a' is a negative index? - * for now, just exit to prevent any segfaults - */ - if (a < 0) return -1; - - /* don't recalculate handles if fast is set - * - this is a hack to make importers faster - * - we may calculate twice (due to autohandle needing to be calculated twice) - */ - if ((flag & INSERTKEY_FAST) == 0) - calchandles_fcurve(fcu); - - /* set handletype and interpolation */ - if ((fcu->totvert > 2) && (flag & INSERTKEY_REPLACE) == 0) { - BezTriple *bezt = (fcu->bezt + a); - - /* set interpolation from previous (if available), but only if we didn't just replace some keyframe - * - replacement is indicated by no-change in number of verts - * - when replacing, the user may have specified some interpolation that should be kept - */ - if (fcu->totvert > oldTot) { - if (a > 0) - bezt->ipo = (bezt - 1)->ipo; - else if (a < fcu->totvert - 1) - bezt->ipo = (bezt + 1)->ipo; - } - - /* don't recalculate handles if fast is set - * - this is a hack to make importers faster - * - we may calculate twice (due to autohandle needing to be calculated twice) - */ - if ((flag & INSERTKEY_FAST) == 0) - calchandles_fcurve(fcu); - } - - /* return the index at which the keyframe was added */ - return a; + BezTriple beztr = {{{0}}}; + unsigned int oldTot = fcu->totvert; + int a; + + /* set all three points, for nicer start position + * NOTE: +/- 1 on vec.x for left and right handles is so that 'free' handles work ok... + */ + beztr.vec[0][0] = x - 1.0f; + beztr.vec[0][1] = y; + beztr.vec[1][0] = x; + beztr.vec[1][1] = y; + beztr.vec[2][0] = x + 1.0f; + beztr.vec[2][1] = y; + beztr.f1 = beztr.f2 = beztr.f3 = SELECT; + + /* set default handle types and interpolation mode */ + if (flag & INSERTKEY_NO_USERPREF) { + /* for Py-API, we want scripts to have predictable behavior, + * hence the option to not depend on the userpref defaults + */ + beztr.h1 = beztr.h2 = HD_AUTO_ANIM; + beztr.ipo = BEZT_IPO_BEZ; + } + else { + /* for UI usage - defaults should come from the userprefs and/or toolsettings */ + beztr.h1 = beztr.h2 = U.keyhandles_new; /* use default handle type here */ + + /* use default interpolation mode, with exceptions for int/discrete values */ + beztr.ipo = U.ipo_new; + } + + /* interpolation type used is constrained by the type of values the curve can take */ + if (fcu->flag & FCURVE_DISCRETE_VALUES) { + beztr.ipo = BEZT_IPO_CONST; + } + else if ((beztr.ipo == BEZT_IPO_BEZ) && (fcu->flag & FCURVE_INT_VALUES)) { + beztr.ipo = BEZT_IPO_LIN; + } + + /* set keyframe type value (supplied), which should come from the scene settings in most cases */ + BEZKEYTYPE(&beztr) = keyframe_type; + + /* set default values for "easing" interpolation mode settings + * NOTE: Even if these modes aren't currently used, if users switch + * to these later, we want these to work in a sane way out of + * the box. + */ + + /* "back" easing - this value used to be used when overshoot=0, but that + * introduced discontinuities in how the param worked. */ + beztr.back = 1.70158f; + + /* "elastic" easing - values here were hand-optimised for a default duration of + * ~10 frames (typical mograph motion length) */ + beztr.amplitude = 0.8f; + beztr.period = 4.1f; + + /* add temp beztriple to keyframes */ + a = insert_bezt_fcurve(fcu, &beztr, flag); + + /* what if 'a' is a negative index? + * for now, just exit to prevent any segfaults + */ + if (a < 0) + return -1; + + /* don't recalculate handles if fast is set + * - this is a hack to make importers faster + * - we may calculate twice (due to autohandle needing to be calculated twice) + */ + if ((flag & INSERTKEY_FAST) == 0) + calchandles_fcurve(fcu); + + /* set handletype and interpolation */ + if ((fcu->totvert > 2) && (flag & INSERTKEY_REPLACE) == 0) { + BezTriple *bezt = (fcu->bezt + a); + + /* set interpolation from previous (if available), but only if we didn't just replace some keyframe + * - replacement is indicated by no-change in number of verts + * - when replacing, the user may have specified some interpolation that should be kept + */ + if (fcu->totvert > oldTot) { + if (a > 0) + bezt->ipo = (bezt - 1)->ipo; + else if (a < fcu->totvert - 1) + bezt->ipo = (bezt + 1)->ipo; + } + + /* don't recalculate handles if fast is set + * - this is a hack to make importers faster + * - we may calculate twice (due to autohandle needing to be calculated twice) + */ + if ((flag & INSERTKEY_FAST) == 0) + calchandles_fcurve(fcu); + } + + /* return the index at which the keyframe was added */ + return a; } /* -------------- 'Smarter' Keyframing Functions -------------------- */ /* return codes for new_key_needed */ enum { - KEYNEEDED_DONTADD = 0, - KEYNEEDED_JUSTADD, - KEYNEEDED_DELPREV, - KEYNEEDED_DELNEXT, + KEYNEEDED_DONTADD = 0, + KEYNEEDED_JUSTADD, + KEYNEEDED_DELPREV, + KEYNEEDED_DELNEXT, } /*eKeyNeededStatus*/; /* This helper function determines whether a new keyframe is needed */ @@ -575,187 +585,195 @@ enum { */ static short new_key_needed(FCurve *fcu, float cFrame, float nValue) { - BezTriple *bezt = NULL, *prev = NULL; - int totCount, i; - float valA = 0.0f, valB = 0.0f; - - /* safety checking */ - if (fcu == NULL) return KEYNEEDED_JUSTADD; - totCount = fcu->totvert; - if (totCount == 0) return KEYNEEDED_JUSTADD; - - /* loop through checking if any are the same */ - bezt = fcu->bezt; - for (i = 0; i < totCount; i++) { - float prevPosi = 0.0f, prevVal = 0.0f; - float beztPosi = 0.0f, beztVal = 0.0f; - - /* get current time+value */ - beztPosi = bezt->vec[1][0]; - beztVal = bezt->vec[1][1]; - - if (prev) { - /* there is a keyframe before the one currently being examined */ - - /* get previous time+value */ - prevPosi = prev->vec[1][0]; - prevVal = prev->vec[1][1]; - - /* keyframe to be added at point where there are already two similar points? */ - if (IS_EQF(prevPosi, cFrame) && IS_EQF(beztPosi, cFrame) && IS_EQF(beztPosi, prevPosi)) { - return KEYNEEDED_DONTADD; - } - - /* keyframe between prev+current points ? */ - if ((prevPosi <= cFrame) && (cFrame <= beztPosi)) { - /* is the value of keyframe to be added the same as keyframes on either side ? */ - if (IS_EQF(prevVal, nValue) && IS_EQF(beztVal, nValue) && IS_EQF(prevVal, beztVal)) { - return KEYNEEDED_DONTADD; - } - else { - float realVal; - - /* get real value of curve at that point */ - realVal = evaluate_fcurve(fcu, cFrame); - - /* compare whether it's the same as proposed */ - if (IS_EQF(realVal, nValue)) - return KEYNEEDED_DONTADD; - else - return KEYNEEDED_JUSTADD; - } - } - - /* new keyframe before prev beztriple? */ - if (cFrame < prevPosi) { - /* A new keyframe will be added. However, whether the previous beztriple - * stays around or not depends on whether the values of previous/current - * beztriples and new keyframe are the same. - */ - if (IS_EQF(prevVal, nValue) && IS_EQF(beztVal, nValue) && IS_EQF(prevVal, beztVal)) - return KEYNEEDED_DELNEXT; - else - return KEYNEEDED_JUSTADD; - } - } - else { - /* just add a keyframe if there's only one keyframe - * and the new one occurs before the existing one does. - */ - if ((cFrame < beztPosi) && (totCount == 1)) - return KEYNEEDED_JUSTADD; - } - - /* continue. frame to do not yet passed (or other conditions not met) */ - if (i < (totCount - 1)) { - prev = bezt; - bezt++; - } - else - break; - } - - /* Frame in which to add a new-keyframe occurs after all other keys - * -> If there are at least two existing keyframes, then if the values of the - * last two keyframes and the new-keyframe match, the last existing keyframe - * gets deleted as it is no longer required. - * -> Otherwise, a keyframe is just added. 1.0 is added so that fake-2nd-to-last - * keyframe is not equal to last keyframe. - */ - bezt = (fcu->bezt + (fcu->totvert - 1)); - valA = bezt->vec[1][1]; - - if (prev) - valB = prev->vec[1][1]; - else - valB = bezt->vec[1][1] + 1.0f; - - if (IS_EQF(valA, nValue) && IS_EQF(valA, valB)) - return KEYNEEDED_DELPREV; - else - return KEYNEEDED_JUSTADD; + BezTriple *bezt = NULL, *prev = NULL; + int totCount, i; + float valA = 0.0f, valB = 0.0f; + + /* safety checking */ + if (fcu == NULL) + return KEYNEEDED_JUSTADD; + totCount = fcu->totvert; + if (totCount == 0) + return KEYNEEDED_JUSTADD; + + /* loop through checking if any are the same */ + bezt = fcu->bezt; + for (i = 0; i < totCount; i++) { + float prevPosi = 0.0f, prevVal = 0.0f; + float beztPosi = 0.0f, beztVal = 0.0f; + + /* get current time+value */ + beztPosi = bezt->vec[1][0]; + beztVal = bezt->vec[1][1]; + + if (prev) { + /* there is a keyframe before the one currently being examined */ + + /* get previous time+value */ + prevPosi = prev->vec[1][0]; + prevVal = prev->vec[1][1]; + + /* keyframe to be added at point where there are already two similar points? */ + if (IS_EQF(prevPosi, cFrame) && IS_EQF(beztPosi, cFrame) && IS_EQF(beztPosi, prevPosi)) { + return KEYNEEDED_DONTADD; + } + + /* keyframe between prev+current points ? */ + if ((prevPosi <= cFrame) && (cFrame <= beztPosi)) { + /* is the value of keyframe to be added the same as keyframes on either side ? */ + if (IS_EQF(prevVal, nValue) && IS_EQF(beztVal, nValue) && IS_EQF(prevVal, beztVal)) { + return KEYNEEDED_DONTADD; + } + else { + float realVal; + + /* get real value of curve at that point */ + realVal = evaluate_fcurve(fcu, cFrame); + + /* compare whether it's the same as proposed */ + if (IS_EQF(realVal, nValue)) + return KEYNEEDED_DONTADD; + else + return KEYNEEDED_JUSTADD; + } + } + + /* new keyframe before prev beztriple? */ + if (cFrame < prevPosi) { + /* A new keyframe will be added. However, whether the previous beztriple + * stays around or not depends on whether the values of previous/current + * beztriples and new keyframe are the same. + */ + if (IS_EQF(prevVal, nValue) && IS_EQF(beztVal, nValue) && IS_EQF(prevVal, beztVal)) + return KEYNEEDED_DELNEXT; + else + return KEYNEEDED_JUSTADD; + } + } + else { + /* just add a keyframe if there's only one keyframe + * and the new one occurs before the existing one does. + */ + if ((cFrame < beztPosi) && (totCount == 1)) + return KEYNEEDED_JUSTADD; + } + + /* continue. frame to do not yet passed (or other conditions not met) */ + if (i < (totCount - 1)) { + prev = bezt; + bezt++; + } + else + break; + } + + /* Frame in which to add a new-keyframe occurs after all other keys + * -> If there are at least two existing keyframes, then if the values of the + * last two keyframes and the new-keyframe match, the last existing keyframe + * gets deleted as it is no longer required. + * -> Otherwise, a keyframe is just added. 1.0 is added so that fake-2nd-to-last + * keyframe is not equal to last keyframe. + */ + bezt = (fcu->bezt + (fcu->totvert - 1)); + valA = bezt->vec[1][1]; + + if (prev) + valB = prev->vec[1][1]; + else + valB = bezt->vec[1][1] + 1.0f; + + if (IS_EQF(valA, nValue) && IS_EQF(valA, valB)) + return KEYNEEDED_DELPREV; + else + return KEYNEEDED_JUSTADD; } /* ------------------ RNA Data-Access Functions ------------------ */ /* Try to read value using RNA-properties obtained already */ -static float *setting_get_rna_values(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, const bool get_evaluated, float *buffer, int buffer_size, int *r_count) +static float *setting_get_rna_values(Depsgraph *depsgraph, + PointerRNA *ptr, + PropertyRNA *prop, + const bool get_evaluated, + float *buffer, + int buffer_size, + int *r_count) { - BLI_assert(buffer_size >= 1); - - float *values = buffer; - PointerRNA ptr_eval; - - if (get_evaluated) { - DEG_get_evaluated_rna_pointer(depsgraph, ptr, &ptr_eval); - ptr = &ptr_eval; - } - - if (RNA_property_array_check(prop)) { - int length = *r_count = RNA_property_array_length(ptr, prop); - bool *tmp_bool; - int *tmp_int; - - if (length > buffer_size) { - values = MEM_malloc_arrayN(sizeof(float), length, __func__); - } - - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - tmp_bool = MEM_malloc_arrayN(sizeof(*tmp_bool), length, __func__); - RNA_property_boolean_get_array(ptr, prop, tmp_bool); - for (int i = 0; i < length; i++) { - values[i] = (float)tmp_bool[i]; - } - MEM_freeN(tmp_bool); - break; - case PROP_INT: - tmp_int = MEM_malloc_arrayN(sizeof(*tmp_int), length, __func__); - RNA_property_int_get_array(ptr, prop, tmp_int); - for (int i = 0; i < length; i++) { - values[i] = (float)tmp_int[i]; - } - MEM_freeN(tmp_int); - break; - case PROP_FLOAT: - RNA_property_float_get_array(ptr, prop, values); - break; - default: - memset(values, 0, sizeof(float) * length); - } - } - else { - *r_count = 1; - - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - *values = (float)RNA_property_boolean_get(ptr, prop); - break; - case PROP_INT: - *values = (float)RNA_property_int_get(ptr, prop); - break; - case PROP_FLOAT: - *values = RNA_property_float_get(ptr, prop); - break; - case PROP_ENUM: - *values = (float)RNA_property_enum_get(ptr, prop); - break; - default: - *values = 0.0f; - } - } - - return values; + BLI_assert(buffer_size >= 1); + + float *values = buffer; + PointerRNA ptr_eval; + + if (get_evaluated) { + DEG_get_evaluated_rna_pointer(depsgraph, ptr, &ptr_eval); + ptr = &ptr_eval; + } + + if (RNA_property_array_check(prop)) { + int length = *r_count = RNA_property_array_length(ptr, prop); + bool *tmp_bool; + int *tmp_int; + + if (length > buffer_size) { + values = MEM_malloc_arrayN(sizeof(float), length, __func__); + } + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + tmp_bool = MEM_malloc_arrayN(sizeof(*tmp_bool), length, __func__); + RNA_property_boolean_get_array(ptr, prop, tmp_bool); + for (int i = 0; i < length; i++) { + values[i] = (float)tmp_bool[i]; + } + MEM_freeN(tmp_bool); + break; + case PROP_INT: + tmp_int = MEM_malloc_arrayN(sizeof(*tmp_int), length, __func__); + RNA_property_int_get_array(ptr, prop, tmp_int); + for (int i = 0; i < length; i++) { + values[i] = (float)tmp_int[i]; + } + MEM_freeN(tmp_int); + break; + case PROP_FLOAT: + RNA_property_float_get_array(ptr, prop, values); + break; + default: + memset(values, 0, sizeof(float) * length); + } + } + else { + *r_count = 1; + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + *values = (float)RNA_property_boolean_get(ptr, prop); + break; + case PROP_INT: + *values = (float)RNA_property_int_get(ptr, prop); + break; + case PROP_FLOAT: + *values = RNA_property_float_get(ptr, prop); + break; + case PROP_ENUM: + *values = (float)RNA_property_enum_get(ptr, prop); + break; + default: + *values = 0.0f; + } + } + + return values; } /* ------------------ 'Visual' Keyframing Functions ------------------ */ /* internal status codes for visualkey_can_use */ enum { - VISUALKEY_NONE = 0, - VISUALKEY_LOC, - VISUALKEY_ROT, - VISUALKEY_SCA, + VISUALKEY_NONE = 0, + VISUALKEY_LOC, + VISUALKEY_ROT, + VISUALKEY_SCA, }; /* This helper function determines if visual-keyframing should be used when @@ -766,331 +784,365 @@ enum { */ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) { - bConstraint *con = NULL; - short searchtype = VISUALKEY_NONE; - bool has_rigidbody = false; - bool has_parent = false; - const char *identifier = NULL; - - /* validate data */ - if (ELEM(NULL, ptr, ptr->data, prop)) - return false; - - /* get first constraint and determine type of keyframe constraints to check for - * - constraints can be on either Objects or PoseChannels, so we only check if the - * ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for - * those structs, allowing us to identify the owner of the data - */ - if (ptr->type == &RNA_Object) { - /* Object */ - Object *ob = (Object *)ptr->data; - RigidBodyOb *rbo = ob->rigidbody_object; - - con = ob->constraints.first; - identifier = RNA_property_identifier(prop); - has_parent = (ob->parent != NULL); - - /* active rigidbody objects only, as only those are affected by sim */ - has_rigidbody = ((rbo) && (rbo->type == RBO_TYPE_ACTIVE)); - } - else if (ptr->type == &RNA_PoseBone) { - /* Pose Channel */ - bPoseChannel *pchan = (bPoseChannel *)ptr->data; - - con = pchan->constraints.first; - identifier = RNA_property_identifier(prop); - has_parent = (pchan->parent != NULL); - } - - /* check if any data to search using */ - if (ELEM(NULL, con, identifier) && (has_parent == false) && (has_rigidbody == false)) - return false; - - /* location or rotation identifiers only... */ - if (identifier == NULL) { - printf("%s failed: NULL identifier\n", __func__); - return false; - } - else if (strstr(identifier, "location")) { - searchtype = VISUALKEY_LOC; - } - else if (strstr(identifier, "rotation")) { - searchtype = VISUALKEY_ROT; - } - else if (strstr(identifier, "scale")) { - searchtype = VISUALKEY_SCA; - } - else { - printf("%s failed: identifier - '%s'\n", __func__, identifier); - return false; - } - - - /* only search if a searchtype and initial constraint are available */ - if (searchtype) { - /* parent or rigidbody are always matching */ - if (has_parent || has_rigidbody) - return true; - - /* constraints */ - for (; con; con = con->next) { - /* only consider constraint if it is not disabled, and has influence */ - if (con->flag & CONSTRAINT_DISABLE) continue; - if (con->enforce == 0.0f) continue; - - /* some constraints may alter these transforms */ - switch (con->type) { - /* multi-transform constraints */ - case CONSTRAINT_TYPE_CHILDOF: - case CONSTRAINT_TYPE_ARMATURE: - return true; - case CONSTRAINT_TYPE_TRANSFORM: - case CONSTRAINT_TYPE_TRANSLIKE: - return true; - case CONSTRAINT_TYPE_FOLLOWPATH: - return true; - case CONSTRAINT_TYPE_KINEMATIC: - return true; - - /* single-transform constraints */ - case CONSTRAINT_TYPE_TRACKTO: - if (searchtype == VISUALKEY_ROT) return true; - break; - case CONSTRAINT_TYPE_DAMPTRACK: - if (searchtype == VISUALKEY_ROT) return true; - break; - case CONSTRAINT_TYPE_ROTLIMIT: - if (searchtype == VISUALKEY_ROT) return true; - break; - case CONSTRAINT_TYPE_LOCLIMIT: - if (searchtype == VISUALKEY_LOC) return true; - break; - case CONSTRAINT_TYPE_SIZELIMIT: - if (searchtype == VISUALKEY_SCA) return true; - break; - case CONSTRAINT_TYPE_DISTLIMIT: - if (searchtype == VISUALKEY_LOC) return true; - break; - case CONSTRAINT_TYPE_ROTLIKE: - if (searchtype == VISUALKEY_ROT) return true; - break; - case CONSTRAINT_TYPE_LOCLIKE: - if (searchtype == VISUALKEY_LOC) return true; - break; - case CONSTRAINT_TYPE_SIZELIKE: - if (searchtype == VISUALKEY_SCA) return true; - break; - case CONSTRAINT_TYPE_LOCKTRACK: - if (searchtype == VISUALKEY_ROT) return true; - break; - case CONSTRAINT_TYPE_MINMAX: - if (searchtype == VISUALKEY_LOC) return true; - break; - - default: - break; - } - } - } - - /* when some condition is met, this function returns, so that means we've got nothing */ - return false; + bConstraint *con = NULL; + short searchtype = VISUALKEY_NONE; + bool has_rigidbody = false; + bool has_parent = false; + const char *identifier = NULL; + + /* validate data */ + if (ELEM(NULL, ptr, ptr->data, prop)) + return false; + + /* get first constraint and determine type of keyframe constraints to check for + * - constraints can be on either Objects or PoseChannels, so we only check if the + * ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for + * those structs, allowing us to identify the owner of the data + */ + if (ptr->type == &RNA_Object) { + /* Object */ + Object *ob = (Object *)ptr->data; + RigidBodyOb *rbo = ob->rigidbody_object; + + con = ob->constraints.first; + identifier = RNA_property_identifier(prop); + has_parent = (ob->parent != NULL); + + /* active rigidbody objects only, as only those are affected by sim */ + has_rigidbody = ((rbo) && (rbo->type == RBO_TYPE_ACTIVE)); + } + else if (ptr->type == &RNA_PoseBone) { + /* Pose Channel */ + bPoseChannel *pchan = (bPoseChannel *)ptr->data; + + con = pchan->constraints.first; + identifier = RNA_property_identifier(prop); + has_parent = (pchan->parent != NULL); + } + + /* check if any data to search using */ + if (ELEM(NULL, con, identifier) && (has_parent == false) && (has_rigidbody == false)) + return false; + + /* location or rotation identifiers only... */ + if (identifier == NULL) { + printf("%s failed: NULL identifier\n", __func__); + return false; + } + else if (strstr(identifier, "location")) { + searchtype = VISUALKEY_LOC; + } + else if (strstr(identifier, "rotation")) { + searchtype = VISUALKEY_ROT; + } + else if (strstr(identifier, "scale")) { + searchtype = VISUALKEY_SCA; + } + else { + printf("%s failed: identifier - '%s'\n", __func__, identifier); + return false; + } + + /* only search if a searchtype and initial constraint are available */ + if (searchtype) { + /* parent or rigidbody are always matching */ + if (has_parent || has_rigidbody) + return true; + + /* constraints */ + for (; con; con = con->next) { + /* only consider constraint if it is not disabled, and has influence */ + if (con->flag & CONSTRAINT_DISABLE) + continue; + if (con->enforce == 0.0f) + continue; + + /* some constraints may alter these transforms */ + switch (con->type) { + /* multi-transform constraints */ + case CONSTRAINT_TYPE_CHILDOF: + case CONSTRAINT_TYPE_ARMATURE: + return true; + case CONSTRAINT_TYPE_TRANSFORM: + case CONSTRAINT_TYPE_TRANSLIKE: + return true; + case CONSTRAINT_TYPE_FOLLOWPATH: + return true; + case CONSTRAINT_TYPE_KINEMATIC: + return true; + + /* single-transform constraints */ + case CONSTRAINT_TYPE_TRACKTO: + if (searchtype == VISUALKEY_ROT) + return true; + break; + case CONSTRAINT_TYPE_DAMPTRACK: + if (searchtype == VISUALKEY_ROT) + return true; + break; + case CONSTRAINT_TYPE_ROTLIMIT: + if (searchtype == VISUALKEY_ROT) + return true; + break; + case CONSTRAINT_TYPE_LOCLIMIT: + if (searchtype == VISUALKEY_LOC) + return true; + break; + case CONSTRAINT_TYPE_SIZELIMIT: + if (searchtype == VISUALKEY_SCA) + return true; + break; + case CONSTRAINT_TYPE_DISTLIMIT: + if (searchtype == VISUALKEY_LOC) + return true; + break; + case CONSTRAINT_TYPE_ROTLIKE: + if (searchtype == VISUALKEY_ROT) + return true; + break; + case CONSTRAINT_TYPE_LOCLIKE: + if (searchtype == VISUALKEY_LOC) + return true; + break; + case CONSTRAINT_TYPE_SIZELIKE: + if (searchtype == VISUALKEY_SCA) + return true; + break; + case CONSTRAINT_TYPE_LOCKTRACK: + if (searchtype == VISUALKEY_ROT) + return true; + break; + case CONSTRAINT_TYPE_MINMAX: + if (searchtype == VISUALKEY_LOC) + return true; + break; + + default: + break; + } + } + } + + /* when some condition is met, this function returns, so that means we've got nothing */ + return false; } /* This helper function extracts the value to use for visual-keyframing * 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_values(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, float *buffer, int buffer_size, int *r_count) +static float *visualkey_get_values(Depsgraph *depsgraph, + PointerRNA *ptr, + PropertyRNA *prop, + float *buffer, + int buffer_size, + int *r_count) { - BLI_assert(buffer_size >= 4); - - const char *identifier = RNA_property_identifier(prop); - float tmat[4][4]; - int rotmode; - - /* handle for Objects or PoseChannels only - * - only Location, Rotation or Scale keyframes are supported currently - * - constraints can be on either Objects or PoseChannels, so we only check if the - * ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for - * those structs, allowing us to identify the owner of the data - * - assume that array_index will be sane - */ - 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")) { - copy_v3_v3(buffer, ob_eval->obmat[3]); - *r_count = 3; - return buffer; - } - - 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; - - 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")) { - /* only use for non-connected bones */ - if ((pchan->bone->parent == NULL) || !(pchan->bone->flag & BONE_CONNECTED)) { - copy_v3_v3(buffer, tmat[3]); - *r_count = 3; - return buffer; - } - } - } - else { - return setting_get_rna_values(depsgraph, ptr, prop, true, buffer, buffer_size, r_count); - } - - /* Rot/Scale code are common! */ - if (strstr(identifier, "rotation_euler")) { - mat4_to_eulO(buffer, rotmode, tmat); - - *r_count = 3; - return buffer; - } - else if (strstr(identifier, "rotation_quaternion")) { - float mat3[3][3]; - - copy_m3_m4(mat3, tmat); - mat3_to_quat_is_ok(buffer, mat3); - - *r_count = 4; - return buffer; - } - else if (strstr(identifier, "rotation_axis_angle")) { - /* w = 0, x,y,z = 1,2,3 */ - mat4_to_axis_angle(buffer + 1, buffer, tmat); - - *r_count = 4; - return buffer; - } - else if (strstr(identifier, "scale")) { - mat4_to_size(buffer, tmat); - - *r_count = 3; - return buffer; - } - - /* as the function hasn't returned yet, read value from system in the default way */ - return setting_get_rna_values(depsgraph, ptr, prop, true, buffer, buffer_size, r_count); + BLI_assert(buffer_size >= 4); + + const char *identifier = RNA_property_identifier(prop); + float tmat[4][4]; + int rotmode; + + /* handle for Objects or PoseChannels only + * - only Location, Rotation or Scale keyframes are supported currently + * - constraints can be on either Objects or PoseChannels, so we only check if the + * ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for + * those structs, allowing us to identify the owner of the data + * - assume that array_index will be sane + */ + 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")) { + copy_v3_v3(buffer, ob_eval->obmat[3]); + *r_count = 3; + return buffer; + } + + 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; + + 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")) { + /* only use for non-connected bones */ + if ((pchan->bone->parent == NULL) || !(pchan->bone->flag & BONE_CONNECTED)) { + copy_v3_v3(buffer, tmat[3]); + *r_count = 3; + return buffer; + } + } + } + else { + return setting_get_rna_values(depsgraph, ptr, prop, true, buffer, buffer_size, r_count); + } + + /* Rot/Scale code are common! */ + if (strstr(identifier, "rotation_euler")) { + mat4_to_eulO(buffer, rotmode, tmat); + + *r_count = 3; + return buffer; + } + else if (strstr(identifier, "rotation_quaternion")) { + float mat3[3][3]; + + copy_m3_m4(mat3, tmat); + mat3_to_quat_is_ok(buffer, mat3); + + *r_count = 4; + return buffer; + } + else if (strstr(identifier, "rotation_axis_angle")) { + /* w = 0, x,y,z = 1,2,3 */ + mat4_to_axis_angle(buffer + 1, buffer, tmat); + + *r_count = 4; + return buffer; + } + else if (strstr(identifier, "scale")) { + mat4_to_size(buffer, tmat); + + *r_count = 3; + return buffer; + } + + /* as the function hasn't returned yet, read value from system in the default way */ + return setting_get_rna_values(depsgraph, ptr, prop, true, buffer, buffer_size, r_count); } /* ------------------------- Insert Key API ------------------------- */ /* Retrieve current property values to keyframe, possibly applying NLA correction when necessary. */ -static float *get_keyframe_values( - Depsgraph *depsgraph, ReportList *reports, PointerRNA ptr, PropertyRNA *prop, int index, - struct NlaKeyframingContext *nla_context, eInsertKeyFlags flag, - float *buffer, int buffer_size, int *r_count, bool *r_force_all) +static float *get_keyframe_values(Depsgraph *depsgraph, + ReportList *reports, + PointerRNA ptr, + PropertyRNA *prop, + int index, + struct NlaKeyframingContext *nla_context, + eInsertKeyFlags flag, + float *buffer, + int buffer_size, + int *r_count, + bool *r_force_all) { - float *values; - - if ( (flag & INSERTKEY_MATRIX) && - (visualkey_can_use(&ptr, prop)) ) - { - /* visual-keying is only available for object and pchan datablocks, as - * it works by keyframing using a value extracted from the final matrix - * instead of using the kt system to extract a value. - */ - values = visualkey_get_values(depsgraph, &ptr, prop, buffer, buffer_size, r_count); - } - else { - /* read value from system */ - values = setting_get_rna_values(depsgraph, &ptr, prop, false, buffer, buffer_size, r_count); - } - - /* adjust the value for NLA factors */ - if (!BKE_animsys_nla_remap_keyframe_values(nla_context, &ptr, prop, values, *r_count, index, r_force_all)) { - BKE_report(reports, RPT_ERROR, "Could not insert keyframe due to zero NLA influence or base value"); - - if (values != buffer) { - MEM_freeN(values); - } - return NULL; - } - - return values; + float *values; + + if ((flag & INSERTKEY_MATRIX) && (visualkey_can_use(&ptr, prop))) { + /* visual-keying is only available for object and pchan datablocks, as + * it works by keyframing using a value extracted from the final matrix + * instead of using the kt system to extract a value. + */ + values = visualkey_get_values(depsgraph, &ptr, prop, buffer, buffer_size, r_count); + } + else { + /* read value from system */ + values = setting_get_rna_values(depsgraph, &ptr, prop, false, buffer, buffer_size, r_count); + } + + /* adjust the value for NLA factors */ + if (!BKE_animsys_nla_remap_keyframe_values( + nla_context, &ptr, prop, values, *r_count, index, r_force_all)) { + BKE_report( + reports, RPT_ERROR, "Could not insert keyframe due to zero NLA influence or base value"); + + if (values != buffer) { + MEM_freeN(values); + } + return NULL; + } + + return values; } /* Insert the specified keyframe value into a single F-Curve. */ -static bool insert_keyframe_value(ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, FCurve *fcu, float cfra, float curval, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag) +static bool insert_keyframe_value(ReportList *reports, + PointerRNA *ptr, + PropertyRNA *prop, + FCurve *fcu, + float cfra, + float curval, + eBezTriple_KeyframeType keytype, + eInsertKeyFlags flag) { - /* F-Curve not editable? */ - if (fcurve_is_keyframable(fcu) == 0) { - BKE_reportf(reports, RPT_ERROR, - "F-Curve with path '%s[%d]' cannot be keyframed, ensure that it is not locked or sampled, " - "and try removing F-Modifiers", - fcu->rna_path, fcu->array_index); - return false; - } - - /* adjust frame on which to add keyframe */ - if ((flag & INSERTKEY_DRIVER) && (fcu->driver)) { - PathResolvedRNA anim_rna; - - 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, fcu->driver, cfra); - } - else { - cfra = 0.0f; - } - } - - /* 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 */ - if (flag & INSERTKEY_NEEDED) { - short insert_mode; - - /* check whether this curve really needs a new keyframe */ - insert_mode = new_key_needed(fcu, cfra, curval); - - /* only return success if keyframe added */ - if (insert_mode == KEYNEEDED_DONTADD) { - return false; - } - - /* insert new keyframe at current frame */ - if (insert_vert_fcurve(fcu, cfra, curval, keytype, flag) < 0) { - return false; - } - - /* delete keyframe immediately before/after newly added */ - switch (insert_mode) { - case KEYNEEDED_DELPREV: - delete_fcurve_key(fcu, fcu->totvert - 2, 1); - break; - case KEYNEEDED_DELNEXT: - delete_fcurve_key(fcu, 1, 1); - break; - } - - return true; - } - else { - /* just insert keyframe */ - return insert_vert_fcurve(fcu, cfra, curval, keytype, flag) >= 0; - } + /* F-Curve not editable? */ + if (fcurve_is_keyframable(fcu) == 0) { + BKE_reportf( + reports, + RPT_ERROR, + "F-Curve with path '%s[%d]' cannot be keyframed, ensure that it is not locked or sampled, " + "and try removing F-Modifiers", + fcu->rna_path, + fcu->array_index); + return false; + } + + /* adjust frame on which to add keyframe */ + if ((flag & INSERTKEY_DRIVER) && (fcu->driver)) { + PathResolvedRNA anim_rna; + + 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, fcu->driver, cfra); + } + else { + cfra = 0.0f; + } + } + + /* 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 */ + if (flag & INSERTKEY_NEEDED) { + short insert_mode; + + /* check whether this curve really needs a new keyframe */ + insert_mode = new_key_needed(fcu, cfra, curval); + + /* only return success if keyframe added */ + if (insert_mode == KEYNEEDED_DONTADD) { + return false; + } + + /* insert new keyframe at current frame */ + if (insert_vert_fcurve(fcu, cfra, curval, keytype, flag) < 0) { + return false; + } + + /* delete keyframe immediately before/after newly added */ + switch (insert_mode) { + case KEYNEEDED_DELPREV: + delete_fcurve_key(fcu, fcu->totvert - 2, 1); + break; + case KEYNEEDED_DELNEXT: + delete_fcurve_key(fcu, 1, 1); + break; + } + + return true; + } + else { + /* just insert keyframe */ + return insert_vert_fcurve(fcu, cfra, curval, keytype, flag) >= 0; + } } /* Secondary Keyframing API call: @@ -1105,104 +1157,134 @@ static bool insert_keyframe_value(ReportList *reports, PointerRNA *ptr, Property * the keyframe insertion. These include the 'visual' keyframing modes, quick refresh, * and extra keyframe filtering. */ -bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, eBezTriple_KeyframeType keytype, struct NlaKeyframingContext *nla_context, eInsertKeyFlags flag) +bool insert_keyframe_direct(Depsgraph *depsgraph, + ReportList *reports, + PointerRNA ptr, + PropertyRNA *prop, + FCurve *fcu, + float cfra, + eBezTriple_KeyframeType keytype, + struct NlaKeyframingContext *nla_context, + eInsertKeyFlags flag) { - float curval = 0.0f; - - /* no F-Curve to add keyframe to? */ - if (fcu == NULL) { - BKE_report(reports, RPT_ERROR, "No F-Curve to add keyframes to"); - return false; - } - - /* if no property given yet, try to validate from F-Curve info */ - if ((ptr.id.data == NULL) && (ptr.data == NULL)) { - BKE_report(reports, RPT_ERROR, "No RNA pointer available to retrieve values for keyframing from"); - return false; - } - if (prop == NULL) { - PointerRNA tmp_ptr; - - /* try to get property we should be affecting */ - if (RNA_path_resolve_property(&ptr, fcu->rna_path, &tmp_ptr, &prop) == false) { - /* property not found... */ - const char *idname = (ptr.id.data) ? ((ID *)ptr.id.data)->name : TIP_("<No ID pointer>"); - - BKE_reportf(reports, RPT_ERROR, - "Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", - idname, fcu->rna_path); - return false; - } - else { - /* property found, so overwrite 'ptr' to make later code easier */ - ptr = tmp_ptr; - } - } - - /* update F-Curve flags to ensure proper behavior for property type */ - update_autoflags_fcurve_direct(fcu, prop); - - /* Obtain the value to insert. */ - float value_buffer[RNA_MAX_ARRAY_LENGTH]; - int value_count; - int index = fcu->array_index; - - float *values = get_keyframe_values(depsgraph, reports, ptr, prop, index, nla_context, flag, - value_buffer, RNA_MAX_ARRAY_LENGTH, &value_count, NULL); - - if (values == NULL) { - /* This happens if NLA rejects this insertion. */ - return false; - } - - if (index >= 0 && index < value_count) { - curval = values[index]; - } - - if (values != value_buffer) { - MEM_freeN(values); - } - - return insert_keyframe_value(reports, &ptr, prop, fcu, cfra, curval, keytype, flag); + float curval = 0.0f; + + /* no F-Curve to add keyframe to? */ + if (fcu == NULL) { + BKE_report(reports, RPT_ERROR, "No F-Curve to add keyframes to"); + return false; + } + + /* if no property given yet, try to validate from F-Curve info */ + if ((ptr.id.data == NULL) && (ptr.data == NULL)) { + BKE_report( + reports, RPT_ERROR, "No RNA pointer available to retrieve values for keyframing from"); + return false; + } + if (prop == NULL) { + PointerRNA tmp_ptr; + + /* try to get property we should be affecting */ + if (RNA_path_resolve_property(&ptr, fcu->rna_path, &tmp_ptr, &prop) == false) { + /* property not found... */ + const char *idname = (ptr.id.data) ? ((ID *)ptr.id.data)->name : TIP_("<No ID pointer>"); + + BKE_reportf(reports, + RPT_ERROR, + "Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, " + "path = %s)", + idname, + fcu->rna_path); + return false; + } + else { + /* property found, so overwrite 'ptr' to make later code easier */ + ptr = tmp_ptr; + } + } + + /* update F-Curve flags to ensure proper behavior for property type */ + update_autoflags_fcurve_direct(fcu, prop); + + /* Obtain the value to insert. */ + float value_buffer[RNA_MAX_ARRAY_LENGTH]; + int value_count; + int index = fcu->array_index; + + float *values = get_keyframe_values(depsgraph, + reports, + ptr, + prop, + index, + nla_context, + flag, + value_buffer, + RNA_MAX_ARRAY_LENGTH, + &value_count, + NULL); + + if (values == NULL) { + /* This happens if NLA rejects this insertion. */ + return false; + } + + if (index >= 0 && index < value_count) { + curval = values[index]; + } + + if (values != value_buffer) { + MEM_freeN(values); + } + + return insert_keyframe_value(reports, &ptr, prop, fcu, cfra, curval, keytype, flag); } /* Find or create the FCurve based on the given path, and insert the specified value into it. */ -static bool insert_keyframe_fcurve_value( - Main *bmain, ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, - bAction *act, const char group[], const char rna_path[], int array_index, - float cfra, float curval, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag) +static bool insert_keyframe_fcurve_value(Main *bmain, + ReportList *reports, + PointerRNA *ptr, + PropertyRNA *prop, + bAction *act, + const char group[], + const char rna_path[], + int array_index, + float cfra, + float curval, + eBezTriple_KeyframeType keytype, + eInsertKeyFlags flag) { - /* make sure the F-Curve exists - * - 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... - */ - FCurve *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) { - /* set color mode if the F-Curve is new (i.e. without any keyframes) */ - if ((fcu->totvert == 0) && (flag & INSERTKEY_XYZ2RGB)) { - /* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor, - * is determined by the array index for the F-Curve - */ - PropertySubType prop_subtype = RNA_property_subtype(prop); - if (ELEM(prop_subtype, PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { - fcu->color_mode = FCURVE_COLOR_AUTO_RGB; - } - else if (ELEM(prop_subtype, PROP_QUATERNION)) { - fcu->color_mode = FCURVE_COLOR_AUTO_YRGB; - } - } - - /* update F-Curve flags to ensure proper behavior for property type */ - update_autoflags_fcurve_direct(fcu, prop); - - /* insert keyframe */ - return insert_keyframe_value(reports, ptr, prop, fcu, cfra, curval, keytype, flag); - } - else { - return false; - } + /* make sure the F-Curve exists + * - 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... + */ + FCurve *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) { + /* set color mode if the F-Curve is new (i.e. without any keyframes) */ + if ((fcu->totvert == 0) && (flag & INSERTKEY_XYZ2RGB)) { + /* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor, + * is determined by the array index for the F-Curve + */ + PropertySubType prop_subtype = RNA_property_subtype(prop); + if (ELEM(prop_subtype, PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { + fcu->color_mode = FCURVE_COLOR_AUTO_RGB; + } + else if (ELEM(prop_subtype, PROP_QUATERNION)) { + fcu->color_mode = FCURVE_COLOR_AUTO_YRGB; + } + } + + /* update F-Curve flags to ensure proper behavior for property type */ + update_autoflags_fcurve_direct(fcu, prop); + + /* insert keyframe */ + return insert_keyframe_value(reports, ptr, prop, fcu, cfra, curval, keytype, flag); + } + else { + return false; + } } /* Main Keyframing API call: @@ -1214,119 +1296,188 @@ static bool insert_keyframe_fcurve_value( * * index of -1 keys all array indices */ -short insert_keyframe( - 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, ListBase *nla_cache, eInsertKeyFlags flag) +short insert_keyframe(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, + ListBase *nla_cache, + eInsertKeyFlags flag) { - PointerRNA id_ptr, ptr; - PropertyRNA *prop = NULL; - AnimData *adt; - ListBase tmp_nla_cache = {NULL, NULL}; - NlaKeyframingContext *nla_context = NULL; - int ret = 0; - - /* validate pointer first - exit if failure */ - if (id == NULL) { - BKE_reportf(reports, RPT_ERROR, "No ID block to insert keyframe in (path = %s)", rna_path); - return 0; - } - - RNA_id_pointer_create(id, &id_ptr); - if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { - BKE_reportf(reports, RPT_ERROR, - "Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", - (id) ? id->name : TIP_("<Missing ID block>"), rna_path); - return 0; - } - - /* if no action is provided, keyframe to the default one attached to this ID-block */ - if (act == NULL) { - /* get action to add F-Curve+keyframe to */ - act = verify_adt_action(bmain, id, 1); - - if (act == NULL) { - BKE_reportf(reports, RPT_ERROR, - "Could not insert keyframe, as this type does not support animation data (ID = %s, path = %s)", - id->name, rna_path); - return 0; - } - } - - /* apply NLA-mapping to frame to use (if applicable) */ - adt = BKE_animdata_from_id(id); - - if (adt && adt->action == act) { - /* Get NLA context for value remapping. */ - nla_context = BKE_animsys_get_nla_keyframing_context(nla_cache ? nla_cache : &tmp_nla_cache, depsgraph, &id_ptr, adt, cfra); - - /* Apply NLA-mapping to frame. */ - cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); - } - - /* Obtain values to insert. */ - float value_buffer[RNA_MAX_ARRAY_LENGTH]; - int value_count; - bool force_all; - - float *values = get_keyframe_values(depsgraph, reports, ptr, prop, array_index, nla_context, flag, - value_buffer, RNA_MAX_ARRAY_LENGTH, &value_count, &force_all); - - if (values != NULL) { - /* Key the entire array. */ - if (array_index == -1 || force_all) { - /* In force mode, if any of the curves succeeds, drop the replace mode and restart. */ - if (force_all && (flag & INSERTKEY_REPLACE) != 0) { - int exclude = -1; - - for (array_index = 0; array_index < value_count; array_index++) { - if (insert_keyframe_fcurve_value(bmain, reports, &ptr, prop, act, group, rna_path, array_index, cfra, values[array_index], keytype, flag)) { - ret++; - exclude = array_index; - break; - } - } - - if (exclude != -1) { - flag &= ~INSERTKEY_REPLACE; - - for (array_index = 0; array_index < value_count; array_index++) { - if (array_index != exclude) { - ret += insert_keyframe_fcurve_value(bmain, reports, &ptr, prop, act, group, rna_path, array_index, cfra, values[array_index], keytype, flag); - } - } - } - } - /* Simply insert all channels. */ - else { - for (array_index = 0; array_index < value_count; array_index++) { - ret += insert_keyframe_fcurve_value(bmain, reports, &ptr, prop, act, group, rna_path, array_index, cfra, values[array_index], keytype, flag); - } - } - } - /* Key a single index. */ - else { - if (array_index >= 0 && array_index < value_count) { - ret += insert_keyframe_fcurve_value(bmain, reports, &ptr, prop, act, group, rna_path, array_index, cfra, values[array_index], keytype, flag); - } - } - } - - if (values != value_buffer) { - MEM_freeN(values); - } - - BKE_animsys_free_nla_keyframing_context_cache(&tmp_nla_cache); - - if (ret) { - if (act != NULL) { - DEG_id_tag_update(&act->id, ID_RECALC_ANIMATION_NO_FLUSH); - } - if (adt != NULL && adt->action != NULL && adt->action != act) { - DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); - } - } - - return ret; + PointerRNA id_ptr, ptr; + PropertyRNA *prop = NULL; + AnimData *adt; + ListBase tmp_nla_cache = {NULL, NULL}; + NlaKeyframingContext *nla_context = NULL; + int ret = 0; + + /* validate pointer first - exit if failure */ + if (id == NULL) { + BKE_reportf(reports, RPT_ERROR, "No ID block to insert keyframe in (path = %s)", rna_path); + return 0; + } + + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { + BKE_reportf( + reports, + RPT_ERROR, + "Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", + (id) ? id->name : TIP_("<Missing ID block>"), + rna_path); + return 0; + } + + /* if no action is provided, keyframe to the default one attached to this ID-block */ + if (act == NULL) { + /* get action to add F-Curve+keyframe to */ + act = verify_adt_action(bmain, id, 1); + + if (act == NULL) { + BKE_reportf(reports, + RPT_ERROR, + "Could not insert keyframe, as this type does not support animation data (ID = " + "%s, path = %s)", + id->name, + rna_path); + return 0; + } + } + + /* apply NLA-mapping to frame to use (if applicable) */ + adt = BKE_animdata_from_id(id); + + if (adt && adt->action == act) { + /* Get NLA context for value remapping. */ + nla_context = BKE_animsys_get_nla_keyframing_context( + nla_cache ? nla_cache : &tmp_nla_cache, depsgraph, &id_ptr, adt, cfra); + + /* Apply NLA-mapping to frame. */ + cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); + } + + /* Obtain values to insert. */ + float value_buffer[RNA_MAX_ARRAY_LENGTH]; + int value_count; + bool force_all; + + float *values = get_keyframe_values(depsgraph, + reports, + ptr, + prop, + array_index, + nla_context, + flag, + value_buffer, + RNA_MAX_ARRAY_LENGTH, + &value_count, + &force_all); + + if (values != NULL) { + /* Key the entire array. */ + if (array_index == -1 || force_all) { + /* In force mode, if any of the curves succeeds, drop the replace mode and restart. */ + if (force_all && (flag & INSERTKEY_REPLACE) != 0) { + int exclude = -1; + + for (array_index = 0; array_index < value_count; array_index++) { + if (insert_keyframe_fcurve_value(bmain, + reports, + &ptr, + prop, + act, + group, + rna_path, + array_index, + cfra, + values[array_index], + keytype, + flag)) { + ret++; + exclude = array_index; + break; + } + } + + if (exclude != -1) { + flag &= ~INSERTKEY_REPLACE; + + for (array_index = 0; array_index < value_count; array_index++) { + if (array_index != exclude) { + ret += insert_keyframe_fcurve_value(bmain, + reports, + &ptr, + prop, + act, + group, + rna_path, + array_index, + cfra, + values[array_index], + keytype, + flag); + } + } + } + } + /* Simply insert all channels. */ + else { + for (array_index = 0; array_index < value_count; array_index++) { + ret += insert_keyframe_fcurve_value(bmain, + reports, + &ptr, + prop, + act, + group, + rna_path, + array_index, + cfra, + values[array_index], + keytype, + flag); + } + } + } + /* Key a single index. */ + else { + if (array_index >= 0 && array_index < value_count) { + ret += insert_keyframe_fcurve_value(bmain, + reports, + &ptr, + prop, + act, + group, + rna_path, + array_index, + cfra, + values[array_index], + keytype, + flag); + } + } + } + + if (values != value_buffer) { + MEM_freeN(values); + } + + BKE_animsys_free_nla_keyframing_context_cache(&tmp_nla_cache); + + if (ret) { + if (act != NULL) { + DEG_id_tag_update(&act->id, ID_RECALC_ANIMATION_NO_FLUSH); + } + if (adt != NULL && adt->action != NULL && adt->action != act) { + DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); + } + } + + return ret; } /* ************************************************** */ @@ -1340,128 +1491,138 @@ short insert_keyframe( * the keyframe deletion. These include the quick refresh options. */ - - /** * \note caller needs to run #BKE_nla_tweakedit_remap to get NLA relative frame. * caller should also check #BKE_fcurve_is_protected before keying. */ static bool delete_keyframe_fcurve(AnimData *adt, FCurve *fcu, float cfra) { - bool found; - int i; - - /* try to find index of beztriple to get rid of */ - i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); - if (found) { - /* delete the key at the index (will sanity check + do recalc afterwards) */ - delete_fcurve_key(fcu, i, 1); - - /* Only delete curve too if it won't be doing anything anymore */ - if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) - ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); - - /* return success */ - return true; - } - return false; + bool found; + int i; + + /* try to find index of beztriple to get rid of */ + i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); + if (found) { + /* delete the key at the index (will sanity check + do recalc afterwards) */ + delete_fcurve_key(fcu, i, 1); + + /* Only delete curve too if it won't be doing anything anymore */ + if ((fcu->totvert == 0) && + (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) + ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); + + /* return success */ + return true; + } + return false; } static void deg_tag_after_keyframe_delete(Main *bmain, ID *id, AnimData *adt) { - if (adt->action == NULL) { - /* In the case last f-curve wes removed need to inform dependency graph - * about relations update, since it needs to get rid of animation operation - * for this datablock. */ - DEG_id_tag_update_ex(bmain, id, ID_RECALC_ANIMATION_NO_FLUSH); - DEG_relations_tag_update(bmain); - } - else { - DEG_id_tag_update_ex(bmain, &adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); - } + if (adt->action == NULL) { + /* In the case last f-curve wes removed need to inform dependency graph + * about relations update, since it needs to get rid of animation operation + * for this datablock. */ + DEG_id_tag_update_ex(bmain, id, ID_RECALC_ANIMATION_NO_FLUSH); + DEG_relations_tag_update(bmain); + } + else { + DEG_id_tag_update_ex(bmain, &adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); + } } -short delete_keyframe(Main *bmain, ReportList *reports, ID *id, bAction *act, - const char group[], const char rna_path[], int array_index, float cfra, +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; - PropertyRNA *prop; - int array_index_max = array_index + 1; - int ret = 0; - - /* sanity checks */ - if (ELEM(NULL, id, adt)) { - BKE_report(reports, RPT_ERROR, "No ID block and/or AnimData to delete keyframe from"); - return 0; - } - - /* validate pointer first - exit if failure */ - RNA_id_pointer_create(id, &id_ptr); - if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { - BKE_reportf(reports, RPT_ERROR, - "Could not delete keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", - id->name, rna_path); - return 0; - } - - /* get F-Curve - * Note: here is one of the places where we don't want new Action + F-Curve added! - * so 'add' var must be 0 - */ - if (act == NULL) { - /* if no action is provided, use the default one attached to this ID-block - * - if it doesn't exist, then we're out of options... - */ - if (adt->action) { - act = adt->action; - - /* apply NLA-mapping to frame to use (if applicable) */ - cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); - } - else { - BKE_reportf(reports, RPT_ERROR, "No action to delete keyframes from for ID = %s", id->name); - return 0; - } - } - - /* key entire array convenience method */ - if (array_index == -1) { - array_index = 0; - array_index_max = RNA_property_array_length(&ptr, prop); - - /* for single properties, increase max_index so that the property itself gets included, - * but don't do this for standard arrays since that can cause corruption issues - * (extra unused curves) - */ - if (array_index_max == array_index) - array_index_max++; - } - - /* will only loop once unless the array index was -1 */ - for (; array_index < array_index_max; array_index++) { - 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) - continue; - - if (BKE_fcurve_is_protected(fcu)) { - BKE_reportf(reports, RPT_WARNING, - "Not deleting keyframe for locked F-Curve '%s' for %s '%s'", - fcu->rna_path, BKE_idcode_to_name(GS(id->name)), id->name + 2); - continue; - } - - ret += delete_keyframe_fcurve(adt, fcu, cfra); - - } - if (ret) { - deg_tag_after_keyframe_delete(bmain, id, adt); - } - /* return success/failure */ - return ret; + AnimData *adt = BKE_animdata_from_id(id); + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + int array_index_max = array_index + 1; + int ret = 0; + + /* sanity checks */ + if (ELEM(NULL, id, adt)) { + BKE_report(reports, RPT_ERROR, "No ID block and/or AnimData to delete keyframe from"); + return 0; + } + + /* validate pointer first - exit if failure */ + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { + BKE_reportf( + reports, + RPT_ERROR, + "Could not delete keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", + id->name, + rna_path); + return 0; + } + + /* get F-Curve + * Note: here is one of the places where we don't want new Action + F-Curve added! + * so 'add' var must be 0 + */ + if (act == NULL) { + /* if no action is provided, use the default one attached to this ID-block + * - if it doesn't exist, then we're out of options... + */ + if (adt->action) { + act = adt->action; + + /* apply NLA-mapping to frame to use (if applicable) */ + cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); + } + else { + BKE_reportf(reports, RPT_ERROR, "No action to delete keyframes from for ID = %s", id->name); + return 0; + } + } + + /* key entire array convenience method */ + if (array_index == -1) { + array_index = 0; + array_index_max = RNA_property_array_length(&ptr, prop); + + /* for single properties, increase max_index so that the property itself gets included, + * but don't do this for standard arrays since that can cause corruption issues + * (extra unused curves) + */ + if (array_index_max == array_index) + array_index_max++; + } + + /* will only loop once unless the array index was -1 */ + for (; array_index < array_index_max; array_index++) { + 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) + continue; + + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf(reports, + RPT_WARNING, + "Not deleting keyframe for locked F-Curve '%s' for %s '%s'", + fcu->rna_path, + BKE_idcode_to_name(GS(id->name)), + id->name + 2); + continue; + } + + ret += delete_keyframe_fcurve(adt, fcu, cfra); + } + if (ret) { + deg_tag_after_keyframe_delete(bmain, id, adt); + } + /* return success/failure */ + return ret; } /* ************************************************** */ @@ -1474,86 +1635,97 @@ short delete_keyframe(Main *bmain, ReportList *reports, ID *id, bAction *act, * 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(Main *bmain, ReportList *reports, ID *id, bAction *act, - const char group[], const char rna_path[], int array_index, +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; - PropertyRNA *prop; - int array_index_max = array_index + 1; - int ret = 0; - - /* sanity checks */ - if (ELEM(NULL, id, adt)) { - BKE_report(reports, RPT_ERROR, "No ID block and/or AnimData to delete keyframe from"); - return 0; - } - - /* validate pointer first - exit if failure */ - RNA_id_pointer_create(id, &id_ptr); - if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { - BKE_reportf(reports, RPT_ERROR, - "Could not clear keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", - id->name, rna_path); - return 0; - } - - /* get F-Curve - * Note: here is one of the places where we don't want new Action + F-Curve added! - * so 'add' var must be 0 - */ - if (act == NULL) { - /* if no action is provided, use the default one attached to this ID-block - * - if it doesn't exist, then we're out of options... - */ - if (adt->action) { - act = adt->action; - } - else { - BKE_reportf(reports, RPT_ERROR, "No action to delete keyframes from for ID = %s", id->name); - return 0; - } - } - - /* key entire array convenience method */ - if (array_index == -1) { - array_index = 0; - array_index_max = RNA_property_array_length(&ptr, prop); - - /* for single properties, increase max_index so that the property itself gets included, - * but don't do this for standard arrays since that can cause corruption issues - * (extra unused curves) - */ - if (array_index_max == array_index) - array_index_max++; - } - - /* will only loop once unless the array index was -1 */ - for (; array_index < array_index_max; array_index++) { - 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) - continue; - - if (BKE_fcurve_is_protected(fcu)) { - BKE_reportf(reports, RPT_WARNING, - "Not clearing all keyframes from locked F-Curve '%s' for %s '%s'", - fcu->rna_path, BKE_idcode_to_name(GS(id->name)), id->name + 2); - continue; - } - - ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); - - /* return success */ - ret++; - } - if (ret) { - deg_tag_after_keyframe_delete(bmain, id, adt); - } - /* return success/failure */ - return ret; + AnimData *adt = BKE_animdata_from_id(id); + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + int array_index_max = array_index + 1; + int ret = 0; + + /* sanity checks */ + if (ELEM(NULL, id, adt)) { + BKE_report(reports, RPT_ERROR, "No ID block and/or AnimData to delete keyframe from"); + return 0; + } + + /* validate pointer first - exit if failure */ + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { + BKE_reportf( + reports, + RPT_ERROR, + "Could not clear keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", + id->name, + rna_path); + return 0; + } + + /* get F-Curve + * Note: here is one of the places where we don't want new Action + F-Curve added! + * so 'add' var must be 0 + */ + if (act == NULL) { + /* if no action is provided, use the default one attached to this ID-block + * - if it doesn't exist, then we're out of options... + */ + if (adt->action) { + act = adt->action; + } + else { + BKE_reportf(reports, RPT_ERROR, "No action to delete keyframes from for ID = %s", id->name); + return 0; + } + } + + /* key entire array convenience method */ + if (array_index == -1) { + array_index = 0; + array_index_max = RNA_property_array_length(&ptr, prop); + + /* for single properties, increase max_index so that the property itself gets included, + * but don't do this for standard arrays since that can cause corruption issues + * (extra unused curves) + */ + if (array_index_max == array_index) + array_index_max++; + } + + /* will only loop once unless the array index was -1 */ + for (; array_index < array_index_max; array_index++) { + 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) + continue; + + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf(reports, + RPT_WARNING, + "Not clearing all keyframes from locked F-Curve '%s' for %s '%s'", + fcu->rna_path, + BKE_idcode_to_name(GS(id->name)), + id->name + 2); + continue; + } + + ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); + + /* return success */ + ret++; + } + if (ret) { + deg_tag_after_keyframe_delete(bmain, id, adt); + } + /* return success/failure */ + return ret; } /* ******************************************* */ @@ -1561,8 +1733,8 @@ static short clear_keyframe(Main *bmain, ReportList *reports, ID *id, bAction *a /* mode for commonkey_modifykey */ enum { - COMMONKEY_MODE_INSERT = 0, - COMMONKEY_MODE_DELETE, + COMMONKEY_MODE_INSERT = 0, + COMMONKEY_MODE_DELETE, } /*eCommonModifyKey_Modes*/; /* Polling callback for use with ANIM_*_keyframe() operators @@ -1571,128 +1743,144 @@ enum { */ static bool modify_key_op_poll(bContext *C) { - ScrArea *sa = CTX_wm_area(C); - Scene *scene = CTX_data_scene(C); + ScrArea *sa = CTX_wm_area(C); + Scene *scene = CTX_data_scene(C); - /* if no area or active scene */ - if (ELEM(NULL, sa, scene)) - return false; + /* if no area or active scene */ + if (ELEM(NULL, sa, scene)) + return false; - /* should be fine */ - return true; + /* should be fine */ + return true; } /* Insert Key Operator ------------------------ */ static int insert_key_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - bool ob_edit_mode = false; - - float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap - short success; - - KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene); - if (ks == NULL) { - return OPERATOR_CANCELLED; - } - - /* exit the edit mode to make sure that those object data properties that have been - * updated since the last switching to the edit mode will be keyframed correctly - */ - if (obedit && ANIM_keyingset_find_id(ks, (ID *)obedit->data)) { - ED_object_mode_toggle(C, OB_MODE_EDIT); - ob_edit_mode = true; - } - - /* try to insert keyframes for the channels specified by KeyingSet */ - success = ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); - if (G.debug & G_DEBUG) - BKE_reportf(op->reports, RPT_INFO, "Keying set '%s' - successfully added %d keyframes", ks->name, success); - - /* restore the edit mode if necessary */ - if (ob_edit_mode) { - ED_object_mode_toggle(C, OB_MODE_EDIT); - } - - /* report failure or do updates? */ - if (success == MODIFYKEY_INVALID_CONTEXT) { - BKE_report(op->reports, RPT_ERROR, "No suitable context info for active keying set"); - return OPERATOR_CANCELLED; - } - else if (success) { - /* if the appropriate properties have been set, make a note that we've inserted something */ - if (RNA_boolean_get(op->ptr, "confirm_success")) - BKE_reportf(op->reports, RPT_INFO, "Successfully added %d keyframes for keying set '%s'", success, ks->name); - - /* send notifiers that keyframes have been changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); - } - else - BKE_report(op->reports, RPT_WARNING, "Keying set failed to insert any keyframes"); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + bool ob_edit_mode = false; + + float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap + short success; + + KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene); + if (ks == NULL) { + return OPERATOR_CANCELLED; + } + + /* exit the edit mode to make sure that those object data properties that have been + * updated since the last switching to the edit mode will be keyframed correctly + */ + if (obedit && ANIM_keyingset_find_id(ks, (ID *)obedit->data)) { + ED_object_mode_toggle(C, OB_MODE_EDIT); + ob_edit_mode = true; + } + + /* try to insert keyframes for the channels specified by KeyingSet */ + success = ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + if (G.debug & G_DEBUG) + BKE_reportf(op->reports, + RPT_INFO, + "Keying set '%s' - successfully added %d keyframes", + ks->name, + success); + + /* restore the edit mode if necessary */ + if (ob_edit_mode) { + ED_object_mode_toggle(C, OB_MODE_EDIT); + } + + /* report failure or do updates? */ + if (success == MODIFYKEY_INVALID_CONTEXT) { + BKE_report(op->reports, RPT_ERROR, "No suitable context info for active keying set"); + return OPERATOR_CANCELLED; + } + else if (success) { + /* if the appropriate properties have been set, make a note that we've inserted something */ + if (RNA_boolean_get(op->ptr, "confirm_success")) + BKE_reportf(op->reports, + RPT_INFO, + "Successfully added %d keyframes for keying set '%s'", + success, + ks->name); + + /* send notifiers that keyframes have been changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); + } + else + BKE_report(op->reports, RPT_WARNING, "Keying set failed to insert any keyframes"); + + return OPERATOR_FINISHED; } void ANIM_OT_keyframe_insert(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Insert Keyframe"; - ot->idname = "ANIM_OT_keyframe_insert"; - ot->description = "Insert keyframes on the current frame for all properties in the specified Keying Set"; - - /* callbacks */ - ot->exec = insert_key_exec; - ot->poll = modify_key_op_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* keyingset to use (dynamic enum) */ - prop = RNA_def_enum(ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); - RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); - RNA_def_property_flag(prop, PROP_HIDDEN); - ot->prop = prop; - - /* confirm whether a keyframe was added by showing a popup - * - by default, this is enabled, since this operator is assumed to be called independently - */ - prop = RNA_def_boolean(ot->srna, "confirm_success", 1, "Confirm Successful Insert", - "Show a popup when the keyframes get successfully added"); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Insert Keyframe"; + ot->idname = "ANIM_OT_keyframe_insert"; + ot->description = + "Insert keyframes on the current frame for all properties in the specified Keying Set"; + + /* callbacks */ + ot->exec = insert_key_exec; + ot->poll = modify_key_op_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* keyingset to use (dynamic enum) */ + prop = RNA_def_enum( + ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); + RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); + RNA_def_property_flag(prop, PROP_HIDDEN); + ot->prop = prop; + + /* confirm whether a keyframe was added by showing a popup + * - by default, this is enabled, since this operator is assumed to be called independently + */ + prop = RNA_def_boolean(ot->srna, + "confirm_success", + 1, + "Confirm Successful Insert", + "Show a popup when the keyframes get successfully added"); + RNA_def_property_flag(prop, PROP_HIDDEN); } /* Clone of 'ANIM_OT_keyframe_insert' which uses a name for the keying set instead of an enum. */ void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Insert Keyframe (by name)"; - ot->idname = "ANIM_OT_keyframe_insert_by_name"; - ot->description = "Alternate access to 'Insert Keyframe' for keymaps to use"; - - /* callbacks */ - ot->exec = insert_key_exec; - ot->poll = modify_key_op_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* keyingset to use (idname) */ - prop = RNA_def_string_file_path(ot->srna, "type", "Type", MAX_ID_NAME - 2, "", ""); - RNA_def_property_flag(prop, PROP_HIDDEN); - ot->prop = prop; - - /* confirm whether a keyframe was added by showing a popup - * - by default, this is enabled, since this operator is assumed to be called independently - */ - prop = RNA_def_boolean(ot->srna, "confirm_success", 1, "Confirm Successful Insert", - "Show a popup when the keyframes get successfully added"); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Insert Keyframe (by name)"; + ot->idname = "ANIM_OT_keyframe_insert_by_name"; + ot->description = "Alternate access to 'Insert Keyframe' for keymaps to use"; + + /* callbacks */ + ot->exec = insert_key_exec; + ot->poll = modify_key_op_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* keyingset to use (idname) */ + prop = RNA_def_string_file_path(ot->srna, "type", "Type", MAX_ID_NAME - 2, "", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + ot->prop = prop; + + /* confirm whether a keyframe was added by showing a popup + * - by default, this is enabled, since this operator is assumed to be called independently + */ + prop = RNA_def_boolean(ot->srna, + "confirm_success", + 1, + "Confirm Successful Insert", + "Show a popup when the keyframes get successfully added"); + RNA_def_property_flag(prop, PROP_HIDDEN); } /* Insert Key Operator (With Menu) ------------------------ */ @@ -1702,190 +1890,207 @@ void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot) static int insert_key_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - Scene *scene = CTX_data_scene(C); - - /* if prompting or no active Keying Set, show the menu */ - if ((scene->active_keyingset == 0) || RNA_boolean_get(op->ptr, "always_prompt")) { - uiPopupMenu *pup; - uiLayout *layout; - - /* call the menu, which will call this operator again, hence the canceled */ - pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE); - layout = UI_popup_menu_layout(pup); - uiItemsEnumO(layout, "ANIM_OT_keyframe_insert_menu", "type"); - UI_popup_menu_end(C, pup); - - return OPERATOR_INTERFACE; - } - else { - /* just call the exec() on the active keyingset */ - RNA_enum_set(op->ptr, "type", 0); - RNA_boolean_set(op->ptr, "confirm_success", true); - - return op->type->exec(C, op); - } + Scene *scene = CTX_data_scene(C); + + /* if prompting or no active Keying Set, show the menu */ + if ((scene->active_keyingset == 0) || RNA_boolean_get(op->ptr, "always_prompt")) { + uiPopupMenu *pup; + uiLayout *layout; + + /* call the menu, which will call this operator again, hence the canceled */ + pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE); + layout = UI_popup_menu_layout(pup); + uiItemsEnumO(layout, "ANIM_OT_keyframe_insert_menu", "type"); + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; + } + else { + /* just call the exec() on the active keyingset */ + RNA_enum_set(op->ptr, "type", 0); + RNA_boolean_set(op->ptr, "confirm_success", true); + + return op->type->exec(C, op); + } } void ANIM_OT_keyframe_insert_menu(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Insert Keyframe Menu"; - ot->idname = "ANIM_OT_keyframe_insert_menu"; - ot->description = "Insert Keyframes for specified Keying Set, with menu of available Keying Sets if undefined"; - - /* callbacks */ - ot->invoke = insert_key_menu_invoke; - ot->exec = insert_key_exec; - ot->poll = ED_operator_areaactive; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* keyingset to use (dynamic enum) */ - prop = RNA_def_enum(ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); - RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); - RNA_def_property_flag(prop, PROP_HIDDEN); - ot->prop = prop; - - /* confirm whether a keyframe was added by showing a popup - * - by default, this is disabled so that if a menu is shown, this doesn't come up too - */ - // XXX should this just be always on? - prop = RNA_def_boolean(ot->srna, "confirm_success", 0, "Confirm Successful Insert", - "Show a popup when the keyframes get successfully added"); - RNA_def_property_flag(prop, PROP_HIDDEN); - - /* whether the menu should always be shown - * - by default, the menu should only be shown when there is no active Keying Set (2.5 behavior), - * although in some cases it might be useful to always shown (pre 2.5 behavior) - */ - prop = RNA_def_boolean(ot->srna, "always_prompt", 0, "Always Show Menu", ""); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Insert Keyframe Menu"; + ot->idname = "ANIM_OT_keyframe_insert_menu"; + ot->description = + "Insert Keyframes for specified Keying Set, with menu of available Keying Sets if undefined"; + + /* callbacks */ + ot->invoke = insert_key_menu_invoke; + ot->exec = insert_key_exec; + ot->poll = ED_operator_areaactive; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* keyingset to use (dynamic enum) */ + prop = RNA_def_enum( + ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); + RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); + RNA_def_property_flag(prop, PROP_HIDDEN); + ot->prop = prop; + + /* confirm whether a keyframe was added by showing a popup + * - by default, this is disabled so that if a menu is shown, this doesn't come up too + */ + // XXX should this just be always on? + prop = RNA_def_boolean(ot->srna, + "confirm_success", + 0, + "Confirm Successful Insert", + "Show a popup when the keyframes get successfully added"); + RNA_def_property_flag(prop, PROP_HIDDEN); + + /* whether the menu should always be shown + * - by default, the menu should only be shown when there is no active Keying Set (2.5 behavior), + * although in some cases it might be useful to always shown (pre 2.5 behavior) + */ + prop = RNA_def_boolean(ot->srna, "always_prompt", 0, "Always Show Menu", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); } /* Delete Key Operator ------------------------ */ static int delete_key_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap - short success; - - KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene); - if (ks == NULL) { - return OPERATOR_CANCELLED; - } - - const int prop_type = RNA_property_type(op->type->prop); - if (prop_type == PROP_ENUM) { - int type = RNA_property_enum_get(op->ptr, op->type->prop); - ks = ANIM_keyingset_get_from_enum_type(scene, type); - if (ks == NULL) { - BKE_report(op->reports, RPT_ERROR, "No active keying set"); - return OPERATOR_CANCELLED; - } - } - else if (prop_type == PROP_STRING) { - char type_id[MAX_ID_NAME - 2]; - RNA_property_string_get(op->ptr, op->type->prop, type_id); - ks = ANIM_keyingset_get_from_idname(scene, type_id); - - if (ks == NULL) { - BKE_reportf(op->reports, RPT_ERROR, "No active keying set '%s' not found", type_id); - return OPERATOR_CANCELLED; - } - } - else { - BLI_assert(0); - } - - /* report failure */ - if (ks == NULL) { - BKE_report(op->reports, RPT_ERROR, "No active Keying Set"); - return OPERATOR_CANCELLED; - } - - /* try to delete keyframes for the channels specified by KeyingSet */ - success = ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_DELETE, cfra); - if (G.debug & G_DEBUG) - printf("KeyingSet '%s' - Successfully removed %d Keyframes\n", ks->name, success); - - /* report failure or do updates? */ - if (success == MODIFYKEY_INVALID_CONTEXT) { - BKE_report(op->reports, RPT_ERROR, "No suitable context info for active keying set"); - return OPERATOR_CANCELLED; - } - else if (success) { - /* if the appropriate properties have been set, make a note that we've inserted something */ - if (RNA_boolean_get(op->ptr, "confirm_success")) - BKE_reportf(op->reports, RPT_INFO, "Successfully removed %d keyframes for keying set '%s'", success, ks->name); - - /* send notifiers that keyframes have been changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); - } - else - BKE_report(op->reports, RPT_WARNING, "Keying set failed to remove any keyframes"); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap + short success; + + KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene); + if (ks == NULL) { + return OPERATOR_CANCELLED; + } + + const int prop_type = RNA_property_type(op->type->prop); + if (prop_type == PROP_ENUM) { + int type = RNA_property_enum_get(op->ptr, op->type->prop); + ks = ANIM_keyingset_get_from_enum_type(scene, type); + if (ks == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active keying set"); + return OPERATOR_CANCELLED; + } + } + else if (prop_type == PROP_STRING) { + char type_id[MAX_ID_NAME - 2]; + RNA_property_string_get(op->ptr, op->type->prop, type_id); + ks = ANIM_keyingset_get_from_idname(scene, type_id); + + if (ks == NULL) { + BKE_reportf(op->reports, RPT_ERROR, "No active keying set '%s' not found", type_id); + return OPERATOR_CANCELLED; + } + } + else { + BLI_assert(0); + } + + /* report failure */ + if (ks == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active Keying Set"); + return OPERATOR_CANCELLED; + } + + /* try to delete keyframes for the channels specified by KeyingSet */ + success = ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_DELETE, cfra); + if (G.debug & G_DEBUG) + printf("KeyingSet '%s' - Successfully removed %d Keyframes\n", ks->name, success); + + /* report failure or do updates? */ + if (success == MODIFYKEY_INVALID_CONTEXT) { + BKE_report(op->reports, RPT_ERROR, "No suitable context info for active keying set"); + return OPERATOR_CANCELLED; + } + else if (success) { + /* if the appropriate properties have been set, make a note that we've inserted something */ + if (RNA_boolean_get(op->ptr, "confirm_success")) + BKE_reportf(op->reports, + RPT_INFO, + "Successfully removed %d keyframes for keying set '%s'", + success, + ks->name); + + /* send notifiers that keyframes have been changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); + } + else + BKE_report(op->reports, RPT_WARNING, "Keying set failed to remove any keyframes"); + + return OPERATOR_FINISHED; } void ANIM_OT_keyframe_delete(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Delete Keying-Set Keyframe"; - ot->idname = "ANIM_OT_keyframe_delete"; - ot->description = "Delete keyframes on the current frame for all properties in the specified Keying Set"; - - /* callbacks */ - ot->exec = delete_key_exec; - ot->poll = modify_key_op_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* keyingset to use (dynamic enum) */ - prop = RNA_def_enum(ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); - RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); - RNA_def_property_flag(prop, PROP_HIDDEN); - ot->prop = prop; - - /* confirm whether a keyframe was added by showing a popup - * - by default, this is enabled, since this operator is assumed to be called independently - */ - RNA_def_boolean(ot->srna, "confirm_success", 1, "Confirm Successful Delete", - "Show a popup when the keyframes get successfully removed"); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Delete Keying-Set Keyframe"; + ot->idname = "ANIM_OT_keyframe_delete"; + ot->description = + "Delete keyframes on the current frame for all properties in the specified Keying Set"; + + /* callbacks */ + ot->exec = delete_key_exec; + ot->poll = modify_key_op_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* keyingset to use (dynamic enum) */ + prop = RNA_def_enum( + ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); + RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); + RNA_def_property_flag(prop, PROP_HIDDEN); + ot->prop = prop; + + /* confirm whether a keyframe was added by showing a popup + * - by default, this is enabled, since this operator is assumed to be called independently + */ + RNA_def_boolean(ot->srna, + "confirm_success", + 1, + "Confirm Successful Delete", + "Show a popup when the keyframes get successfully removed"); } void ANIM_OT_keyframe_delete_by_name(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Delete Keying-Set Keyframe (by name)"; - ot->idname = "ANIM_OT_keyframe_delete_by_name"; - ot->description = "Alternate access to 'Delete Keyframe' for keymaps to use"; - - /* callbacks */ - ot->exec = delete_key_exec; - ot->poll = modify_key_op_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* keyingset to use (idname) */ - prop = RNA_def_string_file_path(ot->srna, "type", "Type", MAX_ID_NAME - 2, "", ""); - RNA_def_property_flag(prop, PROP_HIDDEN); - ot->prop = prop; - - /* confirm whether a keyframe was added by showing a popup - * - by default, this is enabled, since this operator is assumed to be called independently - */ - RNA_def_boolean(ot->srna, "confirm_success", 1, "Confirm Successful Delete", - "Show a popup when the keyframes get successfully removed"); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Delete Keying-Set Keyframe (by name)"; + ot->idname = "ANIM_OT_keyframe_delete_by_name"; + ot->description = "Alternate access to 'Delete Keyframe' for keymaps to use"; + + /* callbacks */ + ot->exec = delete_key_exec; + ot->poll = modify_key_op_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* keyingset to use (idname) */ + prop = RNA_def_string_file_path(ot->srna, "type", "Type", MAX_ID_NAME - 2, "", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + ot->prop = prop; + + /* confirm whether a keyframe was added by showing a popup + * - by default, this is enabled, since this operator is assumed to be called independently + */ + RNA_def_boolean(ot->srna, + "confirm_success", + 1, + "Confirm Successful Delete", + "Show a popup when the keyframes get successfully removed"); } /* Delete Key Operator ------------------------ */ @@ -1895,503 +2100,533 @@ void ANIM_OT_keyframe_delete_by_name(wmOperatorType *ot) static int clear_anim_v3d_exec(bContext *C, wmOperator *UNUSED(op)) { - bool changed = false; - - CTX_DATA_BEGIN (C, Object *, ob, selected_objects) - { - /* just those in active action... */ - if ((ob->adt) && (ob->adt->action)) { - AnimData *adt = ob->adt; - bAction *act = adt->action; - FCurve *fcu, *fcn; - - for (fcu = act->curves.first; fcu; fcu = fcn) { - bool can_delete = false; - - fcn = fcu->next; - - /* in pose mode, only delete the F-Curve if it belongs to a selected bone */ - if (ob->mode & OB_MODE_POSE) { - if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones[")) { - bPoseChannel *pchan; - char *bone_name; - - /* get bone-name, and check if this bone is selected */ - bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(ob->pose, bone_name); - if (bone_name) MEM_freeN(bone_name); - - /* delete if bone is selected*/ - if ((pchan) && (pchan->bone)) { - if (pchan->bone->flag & BONE_SELECTED) - can_delete = true; - } - } - } - else { - /* object mode - all of Object's F-Curves are affected */ - can_delete = true; - } - - /* delete F-Curve completely */ - if (can_delete) { - ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - changed = true; - } - } - } - } - CTX_DATA_END; - - if (!changed) { - return OPERATOR_CANCELLED; - } - - /* send updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); - - return OPERATOR_FINISHED; + bool changed = false; + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + /* just those in active action... */ + if ((ob->adt) && (ob->adt->action)) { + AnimData *adt = ob->adt; + bAction *act = adt->action; + FCurve *fcu, *fcn; + + for (fcu = act->curves.first; fcu; fcu = fcn) { + bool can_delete = false; + + fcn = fcu->next; + + /* in pose mode, only delete the F-Curve if it belongs to a selected bone */ + if (ob->mode & OB_MODE_POSE) { + if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones[")) { + bPoseChannel *pchan; + char *bone_name; + + /* get bone-name, and check if this bone is selected */ + bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); + pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + if (bone_name) + MEM_freeN(bone_name); + + /* delete if bone is selected*/ + if ((pchan) && (pchan->bone)) { + if (pchan->bone->flag & BONE_SELECTED) + can_delete = true; + } + } + } + else { + /* object mode - all of Object's F-Curves are affected */ + can_delete = true; + } + + /* delete F-Curve completely */ + if (can_delete) { + ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + changed = true; + } + } + } + } + CTX_DATA_END; + + if (!changed) { + return OPERATOR_CANCELLED; + } + + /* send updates */ + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); + + return OPERATOR_FINISHED; } void ANIM_OT_keyframe_clear_v3d(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove Animation"; - ot->description = "Remove all keyframe animation for selected objects"; - ot->idname = "ANIM_OT_keyframe_clear_v3d"; + /* identifiers */ + ot->name = "Remove Animation"; + ot->description = "Remove all keyframe animation for selected objects"; + ot->idname = "ANIM_OT_keyframe_clear_v3d"; - /* callbacks */ - ot->invoke = WM_operator_confirm; - ot->exec = clear_anim_v3d_exec; + /* callbacks */ + ot->invoke = WM_operator_confirm; + ot->exec = clear_anim_v3d_exec; - ot->poll = ED_operator_areaactive; + ot->poll = ED_operator_areaactive; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - static int delete_key_v3d_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - float cfra = (float)CFRA; - - CTX_DATA_BEGIN (C, Object *, ob, selected_objects) - { - ID *id = &ob->id; - int success = 0; - - /* just those in active action... */ - if ((ob->adt) && (ob->adt->action)) { - AnimData *adt = ob->adt; - bAction *act = adt->action; - FCurve *fcu, *fcn; - const float cfra_unmap = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); - - for (fcu = act->curves.first; fcu; fcu = fcn) { - fcn = fcu->next; - - /* don't touch protected F-Curves */ - if (BKE_fcurve_is_protected(fcu)) { - BKE_reportf(op->reports, RPT_WARNING, - "Not deleting keyframe for locked F-Curve '%s', object '%s'", - fcu->rna_path, id->name + 2); - continue; - } - - /* special exception for bones, as this makes this operator more convenient to use - * NOTE: This is only done in pose mode. In object mode, we're dealing with the entire object. - */ - if ((ob->mode & OB_MODE_POSE) && strstr(fcu->rna_path, "pose.bones[\"")) { - bPoseChannel *pchan; - char *bone_name; - - /* get bone-name, and check if this bone is selected */ - bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(ob->pose, bone_name); - if (bone_name) MEM_freeN(bone_name); - - /* skip if bone is not selected */ - if ((pchan) && (pchan->bone)) { - /* bones are only selected/editable if visible... */ - bArmature *arm = (bArmature *)ob->data; - - /* skipping - not visible on currently visible layers */ - if ((arm->layer & pchan->bone->layer) == 0) - continue; - /* skipping - is currently hidden */ - if (pchan->bone->flag & BONE_HIDDEN_P) - continue; - - /* selection flag... */ - if ((pchan->bone->flag & BONE_SELECTED) == 0) - continue; - } - } - - /* delete keyframes on current frame - * WARNING: this can delete the next F-Curve, hence the "fcn" copying - */ - success += delete_keyframe_fcurve(adt, fcu, cfra_unmap); - } - DEG_id_tag_update(&ob->adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); - } - - /* report success (or failure) */ - if (success) - BKE_reportf(op->reports, RPT_INFO, "Object '%s' successfully had %d keyframes removed", id->name + 2, success); - else - BKE_reportf(op->reports, RPT_ERROR, "No keyframes removed from Object '%s'", id->name + 2); - - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - } - CTX_DATA_END; - - /* send updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + float cfra = (float)CFRA; + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + ID *id = &ob->id; + int success = 0; + + /* just those in active action... */ + if ((ob->adt) && (ob->adt->action)) { + AnimData *adt = ob->adt; + bAction *act = adt->action; + FCurve *fcu, *fcn; + const float cfra_unmap = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); + + for (fcu = act->curves.first; fcu; fcu = fcn) { + fcn = fcu->next; + + /* don't touch protected F-Curves */ + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf(op->reports, + RPT_WARNING, + "Not deleting keyframe for locked F-Curve '%s', object '%s'", + fcu->rna_path, + id->name + 2); + continue; + } + + /* special exception for bones, as this makes this operator more convenient to use + * NOTE: This is only done in pose mode. In object mode, we're dealing with the entire object. + */ + if ((ob->mode & OB_MODE_POSE) && strstr(fcu->rna_path, "pose.bones[\"")) { + bPoseChannel *pchan; + char *bone_name; + + /* get bone-name, and check if this bone is selected */ + bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); + pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + if (bone_name) + MEM_freeN(bone_name); + + /* skip if bone is not selected */ + if ((pchan) && (pchan->bone)) { + /* bones are only selected/editable if visible... */ + bArmature *arm = (bArmature *)ob->data; + + /* skipping - not visible on currently visible layers */ + if ((arm->layer & pchan->bone->layer) == 0) + continue; + /* skipping - is currently hidden */ + if (pchan->bone->flag & BONE_HIDDEN_P) + continue; + + /* selection flag... */ + if ((pchan->bone->flag & BONE_SELECTED) == 0) + continue; + } + } + + /* delete keyframes on current frame + * WARNING: this can delete the next F-Curve, hence the "fcn" copying + */ + success += delete_keyframe_fcurve(adt, fcu, cfra_unmap); + } + DEG_id_tag_update(&ob->adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); + } + + /* report success (or failure) */ + if (success) + BKE_reportf(op->reports, + RPT_INFO, + "Object '%s' successfully had %d keyframes removed", + id->name + 2, + success); + else + BKE_reportf(op->reports, RPT_ERROR, "No keyframes removed from Object '%s'", id->name + 2); + + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + } + CTX_DATA_END; + + /* send updates */ + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); + + return OPERATOR_FINISHED; } void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Delete Keyframe"; - ot->description = "Remove keyframes on current frame for selected objects and bones"; - ot->idname = "ANIM_OT_keyframe_delete_v3d"; + /* identifiers */ + ot->name = "Delete Keyframe"; + ot->description = "Remove keyframes on current frame for selected objects and bones"; + ot->idname = "ANIM_OT_keyframe_delete_v3d"; - /* callbacks */ - ot->invoke = WM_operator_confirm; - ot->exec = delete_key_v3d_exec; + /* callbacks */ + ot->invoke = WM_operator_confirm; + ot->exec = delete_key_v3d_exec; - ot->poll = ED_operator_areaactive; + ot->poll = ED_operator_areaactive; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - /* Insert Key Button Operator ------------------------ */ 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; - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - char *path; - uiBut *but; - float cfra = (float)CFRA; - short success = 0; - int index; - const bool all = RNA_boolean_get(op->ptr, "all"); - eInsertKeyFlags flag = INSERTKEY_NOFLAGS; - - - /* flags for inserting keyframes */ - flag = ANIM_get_keyframing_flags(scene, 1); - - /* try to insert keyframe using property retrieved from UI */ - if (!(but = UI_context_active_but_prop_get(C, &ptr, &prop, &index))) { - /* pass event on if no active button found */ - return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); - } - - if ((ptr.id.data && ptr.data && prop) && RNA_property_animateable(&ptr, prop)) { - if (ptr.type == &RNA_NlaStrip) { - /* Handle special properties for NLA Strips, whose F-Curves are stored on the - * strips themselves. These are stored separately or else the properties will - * not have any effect. - */ - NlaStrip *strip = (NlaStrip *)ptr.data; - FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); - - if (fcu) { - success = insert_keyframe_direct(depsgraph, op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, NULL, 0); - } - else { - BKE_report(op->reports, RPT_ERROR, - "This property cannot be animated as it will not get updated correctly"); - } - } - else if (UI_but_flag_is_set(but, UI_BUT_DRIVEN)) { - /* Driven property - Find driver */ - FCurve *fcu; - bool driven, special; - - fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special); - - if (fcu && driven) { - success = insert_keyframe_direct(depsgraph, op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, NULL, INSERTKEY_DRIVER); - } - } - else { - /* standard properties */ - 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 behavior in this case. - * - * TODO: Perhaps we can extend this behavior 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, depsgraph, op->reports, ptr.id.data, NULL, group, path, index, cfra, ts->keyframe_type, NULL, flag); - - MEM_freeN(path); - } - else { - BKE_report(op->reports, RPT_WARNING, - "Failed to resolve path to property, " - "try manually specifying this using a Keying Set instead"); - } - } - } - else { - if (prop && !RNA_property_animateable(&ptr, prop)) { - BKE_reportf(op->reports, RPT_WARNING, - "\"%s\" property cannot be animated", - RNA_property_identifier(prop)); - } - else { - BKE_reportf(op->reports, RPT_WARNING, - "Button doesn't appear to have any property information attached (ptr.data = %p, prop = %p)", - (void *)ptr.data, (void *)prop); - } - } - - if (success) { - ID *id = ptr.id.data; - AnimData *adt = BKE_animdata_from_id(id); - if (adt->action != NULL) { - DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); - } - DEG_id_tag_update(id, ID_RECALC_ANIMATION_NO_FLUSH); - - /* send updates */ - UI_context_update_anim_flag(C); - - /* send notifiers that keyframes have been changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); - } - - return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + char *path; + uiBut *but; + float cfra = (float)CFRA; + short success = 0; + int index; + const bool all = RNA_boolean_get(op->ptr, "all"); + eInsertKeyFlags flag = INSERTKEY_NOFLAGS; + + /* flags for inserting keyframes */ + flag = ANIM_get_keyframing_flags(scene, 1); + + /* try to insert keyframe using property retrieved from UI */ + if (!(but = UI_context_active_but_prop_get(C, &ptr, &prop, &index))) { + /* pass event on if no active button found */ + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + if ((ptr.id.data && ptr.data && prop) && RNA_property_animateable(&ptr, prop)) { + if (ptr.type == &RNA_NlaStrip) { + /* Handle special properties for NLA Strips, whose F-Curves are stored on the + * strips themselves. These are stored separately or else the properties will + * not have any effect. + */ + NlaStrip *strip = (NlaStrip *)ptr.data; + FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); + + if (fcu) { + success = insert_keyframe_direct( + depsgraph, op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, NULL, 0); + } + else { + BKE_report(op->reports, + RPT_ERROR, + "This property cannot be animated as it will not get updated correctly"); + } + } + else if (UI_but_flag_is_set(but, UI_BUT_DRIVEN)) { + /* Driven property - Find driver */ + FCurve *fcu; + bool driven, special; + + fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special); + + if (fcu && driven) { + success = insert_keyframe_direct(depsgraph, + op->reports, + ptr, + prop, + fcu, + cfra, + ts->keyframe_type, + NULL, + INSERTKEY_DRIVER); + } + } + else { + /* standard properties */ + 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 behavior in this case. + * + * TODO: Perhaps we can extend this behavior 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, + depsgraph, + op->reports, + ptr.id.data, + NULL, + group, + path, + index, + cfra, + ts->keyframe_type, + NULL, + flag); + + MEM_freeN(path); + } + else { + BKE_report(op->reports, + RPT_WARNING, + "Failed to resolve path to property, " + "try manually specifying this using a Keying Set instead"); + } + } + } + else { + if (prop && !RNA_property_animateable(&ptr, prop)) { + BKE_reportf(op->reports, + RPT_WARNING, + "\"%s\" property cannot be animated", + RNA_property_identifier(prop)); + } + else { + BKE_reportf(op->reports, + RPT_WARNING, + "Button doesn't appear to have any property information attached (ptr.data = " + "%p, prop = %p)", + (void *)ptr.data, + (void *)prop); + } + } + + if (success) { + ID *id = ptr.id.data; + AnimData *adt = BKE_animdata_from_id(id); + if (adt->action != NULL) { + DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); + } + DEG_id_tag_update(id, ID_RECALC_ANIMATION_NO_FLUSH); + + /* send updates */ + UI_context_update_anim_flag(C); + + /* send notifiers that keyframes have been changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); + } + + return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void ANIM_OT_keyframe_insert_button(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Insert Keyframe (Buttons)"; - ot->idname = "ANIM_OT_keyframe_insert_button"; - ot->description = "Insert a keyframe for current UI-active property"; + /* identifiers */ + ot->name = "Insert Keyframe (Buttons)"; + ot->idname = "ANIM_OT_keyframe_insert_button"; + ot->description = "Insert a keyframe for current UI-active property"; - /* callbacks */ - ot->exec = insert_key_button_exec; - ot->poll = modify_key_op_poll; + /* callbacks */ + ot->exec = insert_key_button_exec; + ot->poll = modify_key_op_poll; - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; - /* properties */ - RNA_def_boolean(ot->srna, "all", 1, "All", "Insert a keyframe for all element of the array"); + /* properties */ + RNA_def_boolean(ot->srna, "all", 1, "All", "Insert a keyframe for all element of the array"); } /* Delete Key Button Operator ------------------------ */ 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; - int index; - const bool all = RNA_boolean_get(op->ptr, "all"); - - /* try to insert keyframe using property retrieved from UI */ - if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) { - /* pass event on if no active button found */ - return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); - } - - if (ptr.id.data && ptr.data && prop) { - if (BKE_nlastrip_has_curves_for_property(&ptr, prop)) { - /* Handle special properties for NLA Strips, whose F-Curves are stored on the - * strips themselves. These are stored separately or else the properties will - * not have any effect. - */ - ID *id = ptr.id.data; - NlaStrip *strip = (NlaStrip *)ptr.data; - FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0); - - if (fcu) { - if (BKE_fcurve_is_protected(fcu)) { - BKE_reportf(op->reports, RPT_WARNING, - "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'", - strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2); - } - else { - /* remove the keyframe directly - * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve, - * and delete_keyframe() expects the FCurve to be part of an action - */ - bool found = false; - int i; - - /* try to find index of beztriple to get rid of */ - i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); - if (found) { - /* delete the key at the index (will sanity check + do recalc afterwards) */ - delete_fcurve_key(fcu, i, 1); - success = true; - } - } - } - } - else { - /* standard properties */ - path = RNA_path_from_ID_to_property(&ptr, prop); - - if (path) { - if (all) { - /* -1 indicates operating on the entire array (or the property itself otherwise) */ - index = -1; - } - - success = delete_keyframe(bmain, op->reports, ptr.id.data, NULL, NULL, path, index, cfra, 0); - MEM_freeN(path); - } - else if (G.debug & G_DEBUG) - printf("Button Delete-Key: no path to property\n"); - } - } - else if (G.debug & G_DEBUG) { - printf("ptr.data = %p, prop = %p\n", (void *)ptr.data, (void *)prop); - } - - - if (success) { - /* send updates */ - UI_context_update_anim_flag(C); - - /* send notifiers that keyframes have been changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); - } - - return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + 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; + int index; + const bool all = RNA_boolean_get(op->ptr, "all"); + + /* try to insert keyframe using property retrieved from UI */ + if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) { + /* pass event on if no active button found */ + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + if (ptr.id.data && ptr.data && prop) { + if (BKE_nlastrip_has_curves_for_property(&ptr, prop)) { + /* Handle special properties for NLA Strips, whose F-Curves are stored on the + * strips themselves. These are stored separately or else the properties will + * not have any effect. + */ + ID *id = ptr.id.data; + NlaStrip *strip = (NlaStrip *)ptr.data; + FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0); + + if (fcu) { + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf( + op->reports, + RPT_WARNING, + "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'", + strip->name, + BKE_idcode_to_name(GS(id->name)), + id->name + 2); + } + else { + /* remove the keyframe directly + * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve, + * and delete_keyframe() expects the FCurve to be part of an action + */ + bool found = false; + int i; + + /* try to find index of beztriple to get rid of */ + i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); + if (found) { + /* delete the key at the index (will sanity check + do recalc afterwards) */ + delete_fcurve_key(fcu, i, 1); + success = true; + } + } + } + } + else { + /* standard properties */ + path = RNA_path_from_ID_to_property(&ptr, prop); + + if (path) { + if (all) { + /* -1 indicates operating on the entire array (or the property itself otherwise) */ + index = -1; + } + + success = delete_keyframe( + bmain, op->reports, ptr.id.data, NULL, NULL, path, index, cfra, 0); + MEM_freeN(path); + } + else if (G.debug & G_DEBUG) + printf("Button Delete-Key: no path to property\n"); + } + } + else if (G.debug & G_DEBUG) { + printf("ptr.data = %p, prop = %p\n", (void *)ptr.data, (void *)prop); + } + + if (success) { + /* send updates */ + UI_context_update_anim_flag(C); + + /* send notifiers that keyframes have been changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); + } + + return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void ANIM_OT_keyframe_delete_button(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Delete Keyframe (Buttons)"; - ot->idname = "ANIM_OT_keyframe_delete_button"; - ot->description = "Delete current keyframe of current UI-active property"; + /* identifiers */ + ot->name = "Delete Keyframe (Buttons)"; + ot->idname = "ANIM_OT_keyframe_delete_button"; + ot->description = "Delete current keyframe of current UI-active property"; - /* callbacks */ - ot->exec = delete_key_button_exec; - ot->poll = modify_key_op_poll; + /* callbacks */ + ot->exec = delete_key_button_exec; + ot->poll = modify_key_op_poll; - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; - /* properties */ - RNA_def_boolean(ot->srna, "all", 1, "All", "Delete keyframes from all elements of the array"); + /* properties */ + RNA_def_boolean(ot->srna, "all", 1, "All", "Delete keyframes from all elements of the array"); } - /* Clear Key Button Operator ------------------------ */ 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; - const bool all = RNA_boolean_get(op->ptr, "all"); - - /* try to insert keyframe using property retrieved from UI */ - if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) { - /* pass event on if no active button found */ - return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); - } - - if (ptr.id.data && ptr.data && prop) { - path = RNA_path_from_ID_to_property(&ptr, prop); - - if (path) { - if (all) { - /* -1 indicates operating on the entire array (or the property itself otherwise) */ - index = -1; - } - - success += clear_keyframe(bmain, op->reports, ptr.id.data, NULL, NULL, path, index, 0); - MEM_freeN(path); - } - else if (G.debug & G_DEBUG) - printf("Button Clear-Key: no path to property\n"); - } - else if (G.debug & G_DEBUG) { - printf("ptr.data = %p, prop = %p\n", (void *)ptr.data, (void *)prop); - } - - - if (success) { - /* send updates */ - UI_context_update_anim_flag(C); - - /* send notifiers that keyframes have been changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); - } - - return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + Main *bmain = CTX_data_main(C); + char *path; + short success = 0; + int index; + const bool all = RNA_boolean_get(op->ptr, "all"); + + /* try to insert keyframe using property retrieved from UI */ + if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) { + /* pass event on if no active button found */ + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + if (ptr.id.data && ptr.data && prop) { + path = RNA_path_from_ID_to_property(&ptr, prop); + + if (path) { + if (all) { + /* -1 indicates operating on the entire array (or the property itself otherwise) */ + index = -1; + } + + success += clear_keyframe(bmain, op->reports, ptr.id.data, NULL, NULL, path, index, 0); + MEM_freeN(path); + } + else if (G.debug & G_DEBUG) + printf("Button Clear-Key: no path to property\n"); + } + else if (G.debug & G_DEBUG) { + printf("ptr.data = %p, prop = %p\n", (void *)ptr.data, (void *)prop); + } + + if (success) { + /* send updates */ + UI_context_update_anim_flag(C); + + /* send notifiers that keyframes have been changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); + } + + return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void ANIM_OT_keyframe_clear_button(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Keyframe (Buttons)"; - ot->idname = "ANIM_OT_keyframe_clear_button"; - ot->description = "Clear all keyframes on the currently active property"; + /* identifiers */ + ot->name = "Clear Keyframe (Buttons)"; + ot->idname = "ANIM_OT_keyframe_clear_button"; + ot->description = "Clear all keyframes on the currently active property"; - /* callbacks */ - ot->exec = clear_key_button_exec; - ot->poll = modify_key_op_poll; + /* callbacks */ + ot->exec = clear_key_button_exec; + ot->poll = modify_key_op_poll; - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; - /* properties */ - RNA_def_boolean(ot->srna, "all", 1, "All", "Clear keyframes from all elements of the array"); + /* properties */ + RNA_def_boolean(ot->srna, "all", 1, "All", "Clear keyframes from all elements of the array"); } /* ******************************************* */ @@ -2399,30 +2634,30 @@ void ANIM_OT_keyframe_clear_button(wmOperatorType *ot) bool autokeyframe_cfra_can_key(Scene *scene, ID *id) { - float cfra = (float)CFRA; // XXX for now, this will do - - /* only filter if auto-key mode requires this */ - if (IS_AUTOKEY_ON(scene) == 0) - return false; - - if (IS_AUTOKEY_MODE(scene, EDITKEYS)) { - /* Replace Mode: - * For whole block, only key if there's a keyframe on that frame already - * This is a valid assumption when we're blocking + tweaking - */ - return id_frame_has_keyframe(id, cfra, ANIMFILTER_KEYS_LOCAL); - } - else { - /* Normal Mode (or treat as being normal mode): - * - * Just in case the flags aren't set properly (i.e. only on/off is set, without a mode) - * let's set the "normal" flag too, so that it will all be sane everywhere... - */ - scene->toolsettings->autokey_mode = AUTOKEY_MODE_NORMAL; - - /* Can insert anytime we like... */ - return true; - } + float cfra = (float)CFRA; // XXX for now, this will do + + /* only filter if auto-key mode requires this */ + if (IS_AUTOKEY_ON(scene) == 0) + return false; + + if (IS_AUTOKEY_MODE(scene, EDITKEYS)) { + /* Replace Mode: + * For whole block, only key if there's a keyframe on that frame already + * This is a valid assumption when we're blocking + tweaking + */ + return id_frame_has_keyframe(id, cfra, ANIMFILTER_KEYS_LOCAL); + } + else { + /* Normal Mode (or treat as being normal mode): + * + * Just in case the flags aren't set properly (i.e. only on/off is set, without a mode) + * let's set the "normal" flag too, so that it will all be sane everywhere... + */ + scene->toolsettings->autokey_mode = AUTOKEY_MODE_NORMAL; + + /* Can insert anytime we like... */ + return true; + } } /* ******************************************* */ @@ -2433,48 +2668,49 @@ bool autokeyframe_cfra_can_key(Scene *scene, ID *id) /* Checks if some F-Curve has a keyframe for a given frame */ bool fcurve_frame_has_keyframe(FCurve *fcu, float frame, short filter) { - /* quick sanity check */ - if (ELEM(NULL, fcu, fcu->bezt)) - return false; - - /* we either include all regardless of muting, or only non-muted */ - if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED) == 0) { - bool replace; - int i = binarysearch_bezt_index(fcu->bezt, frame, fcu->totvert, &replace); - - /* binarysearch_bezt_index will set replace to be 0 or 1 - * - obviously, 1 represents a match - */ - if (replace) { - /* sanity check: 'i' may in rare cases exceed arraylen */ - if ((i >= 0) && (i < fcu->totvert)) - return true; - } - } - - return false; + /* quick sanity check */ + if (ELEM(NULL, fcu, fcu->bezt)) + return false; + + /* we either include all regardless of muting, or only non-muted */ + if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED) == 0) { + bool replace; + int i = binarysearch_bezt_index(fcu->bezt, frame, fcu->totvert, &replace); + + /* binarysearch_bezt_index will set replace to be 0 or 1 + * - obviously, 1 represents a match + */ + if (replace) { + /* sanity check: 'i' may in rare cases exceed arraylen */ + if ((i >= 0) && (i < fcu->totvert)) + return true; + } + } + + return false; } /* Returns whether the current value of a given property differs from the interpolated value. */ bool fcurve_is_changed(PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float frame) { - PathResolvedRNA anim_rna; - anim_rna.ptr = ptr; - anim_rna.prop = prop; - anim_rna.prop_index = fcu->array_index; + PathResolvedRNA anim_rna; + anim_rna.ptr = ptr; + anim_rna.prop = prop; + anim_rna.prop_index = fcu->array_index; - float buffer[RNA_MAX_ARRAY_LENGTH]; - int count, index = fcu->array_index; - float *values = setting_get_rna_values(NULL, &ptr, prop, false, buffer, RNA_MAX_ARRAY_LENGTH, &count); + float buffer[RNA_MAX_ARRAY_LENGTH]; + int count, index = fcu->array_index; + float *values = setting_get_rna_values( + NULL, &ptr, prop, false, buffer, RNA_MAX_ARRAY_LENGTH, &count); - float fcurve_val = calculate_fcurve(&anim_rna, fcu, frame); - float cur_val = (index >= 0 && index < count) ? values[index] : 0.0f; + float fcurve_val = calculate_fcurve(&anim_rna, fcu, frame); + float cur_val = (index >= 0 && index < count) ? values[index] : 0.0f; - if (values != buffer) { - MEM_freeN(values); - } + if (values != buffer) { + MEM_freeN(values); + } - return !compare_ff_relative(fcurve_val, cur_val, FLT_EPSILON, 64); + return !compare_ff_relative(fcurve_val, cur_val, FLT_EPSILON, 64); } /* Checks whether an Action has a keyframe for a given frame @@ -2482,91 +2718,91 @@ bool fcurve_is_changed(PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float fra */ static bool action_frame_has_keyframe(bAction *act, float frame, short filter) { - FCurve *fcu; - - /* can only find if there is data */ - if (act == NULL) - return false; - - /* if only check non-muted, check if muted */ - if ((filter & ANIMFILTER_KEYS_MUTED) || (act->flag & ACT_MUTED)) - return false; - - /* loop over F-Curves, using binary-search to try to find matches - * - this assumes that keyframes are only beztriples - */ - for (fcu = act->curves.first; fcu; fcu = fcu->next) { - /* only check if there are keyframes (currently only of type BezTriple) */ - if (fcu->bezt && fcu->totvert) { - if (fcurve_frame_has_keyframe(fcu, frame, filter)) - return true; - } - } - - /* nothing found */ - return false; + FCurve *fcu; + + /* can only find if there is data */ + if (act == NULL) + return false; + + /* if only check non-muted, check if muted */ + if ((filter & ANIMFILTER_KEYS_MUTED) || (act->flag & ACT_MUTED)) + return false; + + /* loop over F-Curves, using binary-search to try to find matches + * - this assumes that keyframes are only beztriples + */ + for (fcu = act->curves.first; fcu; fcu = fcu->next) { + /* only check if there are keyframes (currently only of type BezTriple) */ + if (fcu->bezt && fcu->totvert) { + if (fcurve_frame_has_keyframe(fcu, frame, filter)) + return true; + } + } + + /* nothing found */ + return false; } /* Checks whether an Object has a keyframe for a given frame */ static bool object_frame_has_keyframe(Object *ob, float frame, short filter) { - /* error checking */ - if (ob == NULL) - return false; - - /* check own animation data - specifically, the action it contains */ - if ((ob->adt) && (ob->adt->action)) { - /* T41525 - When the active action is a NLA strip being edited, - * we need to correct the frame number to "look inside" the - * remapped action - */ - float ob_frame = BKE_nla_tweakedit_remap(ob->adt, frame, NLATIME_CONVERT_UNMAP); - - if (action_frame_has_keyframe(ob->adt->action, ob_frame, filter)) - return true; - } - - /* try shapekey keyframes (if available, and allowed by filter) */ - if (!(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOSKEY)) { - Key *key = BKE_key_from_object(ob); - - /* shapekeys can have keyframes ('Relative Shape Keys') - * or depend on time (old 'Absolute Shape Keys') - */ - - /* 1. test for relative (with keyframes) */ - if (id_frame_has_keyframe((ID *)key, frame, filter)) - return true; - - /* 2. test for time */ - /* TODO... yet to be implemented (this feature may evolve before then anyway) */ - } - - /* try materials */ - if (!(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOMAT)) { - /* if only active, then we can skip a lot of looping */ - if (filter & ANIMFILTER_KEYS_ACTIVE) { - Material *ma = give_current_material(ob, (ob->actcol + 1)); - - /* we only retrieve the active material... */ - if (id_frame_has_keyframe((ID *)ma, frame, filter)) - return true; - } - else { - int a; - - /* loop over materials */ - for (a = 0; a < ob->totcol; a++) { - Material *ma = give_current_material(ob, a + 1); - - if (id_frame_has_keyframe((ID *)ma, frame, filter)) - return true; - } - } - } - - /* nothing found */ - return false; + /* error checking */ + if (ob == NULL) + return false; + + /* check own animation data - specifically, the action it contains */ + if ((ob->adt) && (ob->adt->action)) { + /* T41525 - When the active action is a NLA strip being edited, + * we need to correct the frame number to "look inside" the + * remapped action + */ + float ob_frame = BKE_nla_tweakedit_remap(ob->adt, frame, NLATIME_CONVERT_UNMAP); + + if (action_frame_has_keyframe(ob->adt->action, ob_frame, filter)) + return true; + } + + /* try shapekey keyframes (if available, and allowed by filter) */ + if (!(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOSKEY)) { + Key *key = BKE_key_from_object(ob); + + /* shapekeys can have keyframes ('Relative Shape Keys') + * or depend on time (old 'Absolute Shape Keys') + */ + + /* 1. test for relative (with keyframes) */ + if (id_frame_has_keyframe((ID *)key, frame, filter)) + return true; + + /* 2. test for time */ + /* TODO... yet to be implemented (this feature may evolve before then anyway) */ + } + + /* try materials */ + if (!(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOMAT)) { + /* if only active, then we can skip a lot of looping */ + if (filter & ANIMFILTER_KEYS_ACTIVE) { + Material *ma = give_current_material(ob, (ob->actcol + 1)); + + /* we only retrieve the active material... */ + if (id_frame_has_keyframe((ID *)ma, frame, filter)) + return true; + } + else { + int a; + + /* loop over materials */ + for (a = 0; a < ob->totcol; a++) { + Material *ma = give_current_material(ob, a + 1); + + if (id_frame_has_keyframe((ID *)ma, frame, filter)) + return true; + } + } + } + + /* nothing found */ + return false; } /* --------------- API ------------------- */ @@ -2574,88 +2810,88 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter) /* Checks whether a keyframe exists for the given ID-block one the given frame */ bool id_frame_has_keyframe(ID *id, float frame, short filter) { - /* sanity checks */ - if (id == NULL) - return false; - - /* perform special checks for 'macro' types */ - switch (GS(id->name)) { - case ID_OB: /* object */ - return object_frame_has_keyframe((Object *)id, frame, filter); + /* sanity checks */ + if (id == NULL) + return false; + + /* perform special checks for 'macro' types */ + switch (GS(id->name)) { + case ID_OB: /* object */ + return object_frame_has_keyframe((Object *)id, frame, filter); #if 0 - // XXX TODO... for now, just use 'normal' behavior - case ID_SCE: /* scene */ - break; + // XXX TODO... for now, just use 'normal' behavior + case ID_SCE: /* scene */ + break; #endif - default: /* 'normal type' */ - { - AnimData *adt = BKE_animdata_from_id(id); - - /* only check keyframes in active action */ - if (adt) - return action_frame_has_keyframe(adt->action, frame, filter); - break; - } - } - - - /* no keyframe found */ - return false; + default: /* 'normal type' */ + { + AnimData *adt = BKE_animdata_from_id(id); + + /* only check keyframes in active action */ + if (adt) + return action_frame_has_keyframe(adt->action, frame, filter); + break; + } + } + + /* no keyframe found */ + return false; } /* ************************************************** */ bool ED_autokeyframe_object(bContext *C, Scene *scene, Object *ob, KeyingSet *ks) { - /* auto keyframing */ - if (autokeyframe_cfra_can_key(scene, &ob->id)) { - ListBase dsources = {NULL, NULL}; - - /* now insert the keyframe(s) using the Keying Set - * 1) add datasource override for the Object - * 2) insert keyframes - * 3) free the extra info - */ - ANIM_relative_keyingset_add_source(&dsources, &ob->id, NULL, NULL); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); - BLI_freelistN(&dsources); - - return true; - } - else { - return false; - } + /* auto keyframing */ + if (autokeyframe_cfra_can_key(scene, &ob->id)) { + ListBase dsources = {NULL, NULL}; + + /* now insert the keyframe(s) using the Keying Set + * 1) add datasource override for the Object + * 2) insert keyframes + * 3) free the extra info + */ + ANIM_relative_keyingset_add_source(&dsources, &ob->id, NULL, NULL); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + BLI_freelistN(&dsources); + + return true; + } + else { + return false; + } } -bool ED_autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel *pchan, KeyingSet *ks) +bool ED_autokeyframe_pchan( + bContext *C, Scene *scene, Object *ob, bPoseChannel *pchan, KeyingSet *ks) { - if (autokeyframe_cfra_can_key(scene, &ob->id)) { - ListBase dsources = {NULL, NULL}; - - /* now insert the keyframe(s) using the Keying Set - * 1) add datasource override for the PoseChannel - * 2) insert keyframes - * 3) free the extra info - */ - ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); - BLI_freelistN(&dsources); - - /* clear any unkeyed tags */ - if (pchan->bone) { - pchan->bone->flag &= ~BONE_UNKEYED; - } - - return true; - } - else { - /* add unkeyed tags */ - if (pchan->bone) { - pchan->bone->flag |= BONE_UNKEYED; - } - - return false; - } + if (autokeyframe_cfra_can_key(scene, &ob->id)) { + ListBase dsources = {NULL, NULL}; + + /* now insert the keyframe(s) using the Keying Set + * 1) add datasource override for the PoseChannel + * 2) insert keyframes + * 3) free the extra info + */ + ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + BLI_freelistN(&dsources); + + /* clear any unkeyed tags */ + if (pchan->bone) { + pchan->bone->flag &= ~BONE_UNKEYED; + } + + return true; + } + else { + /* add unkeyed tags */ + if (pchan->bone) { + pchan->bone->flag |= BONE_UNKEYED; + } + + return false; + } } /* -------------------------------------------------------------------- */ @@ -2665,28 +2901,28 @@ bool ED_autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel * /** Use for insert/delete key-frame. */ static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op, PropertyRNA *prop, Scene *scene) { - KeyingSet *ks = NULL; - const int prop_type = RNA_property_type(prop); - if (prop_type == PROP_ENUM) { - int type = RNA_property_enum_get(op->ptr, prop); - ks = ANIM_keyingset_get_from_enum_type(scene, type); - if (ks == NULL) { - BKE_report(op->reports, RPT_ERROR, "No active keying set"); - } - } - else if (prop_type == PROP_STRING) { - char type_id[MAX_ID_NAME - 2]; - RNA_property_string_get(op->ptr, prop, type_id); - ks = ANIM_keyingset_get_from_idname(scene, type_id); - - if (ks == NULL) { - BKE_reportf(op->reports, RPT_ERROR, "Keying set '%s' not found", type_id); - } - } - else { - BLI_assert(0); - } - return ks; + KeyingSet *ks = NULL; + const int prop_type = RNA_property_type(prop); + if (prop_type == PROP_ENUM) { + int type = RNA_property_enum_get(op->ptr, prop); + ks = ANIM_keyingset_get_from_enum_type(scene, type); + if (ks == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active keying set"); + } + } + else if (prop_type == PROP_STRING) { + char type_id[MAX_ID_NAME - 2]; + RNA_property_string_get(op->ptr, prop, type_id); + ks = ANIM_keyingset_get_from_idname(scene, type_id); + + if (ks == NULL) { + BKE_reportf(op->reports, RPT_ERROR, "Keying set '%s' not found", type_id); + } + } + else { + BLI_assert(0); + } + return ks; } /** \} */ |