diff options
Diffstat (limited to 'source/blender/editors/animation/keyframing.c')
-rw-r--r-- | source/blender/editors/animation/keyframing.c | 305 |
1 files changed, 212 insertions, 93 deletions
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 8d079641e9f..5b742ddf272 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -14,6 +14,7 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_dynstr.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -1109,9 +1110,62 @@ static float *visualkey_get_values( /* ------------------------- Insert Key API ------------------------- */ +/* Check indices that were intended to be remapped and report any failed remaps. */ +static void get_keyframe_values_create_reports(ReportList *reports, + PointerRNA ptr, + PropertyRNA *prop, + const int index, + const int count, + const bool force_all, + const BLI_bitmap *successful_remaps) +{ + + DynStr *ds_failed_indices = BLI_dynstr_new(); + + int total_failed = 0; + for (int i = 0; i < count; i++) { + const bool cur_index_evaluated = ELEM(index, i, -1) || force_all; + if (!cur_index_evaluated) { + /* values[i] was never intended to be remapped. */ + continue; + } + + if (BLI_BITMAP_TEST_BOOL(successful_remaps, i)) { + /* values[i] succesfully remapped. */ + continue; + } + + total_failed++; + /* Report that values[i] were intended to be remapped but failed remapping process. */ + BLI_dynstr_appendf(ds_failed_indices, "%d, ", i); + } + + if (total_failed == 0) { + BLI_dynstr_free(ds_failed_indices); + return; + } + + char *str_failed_indices = BLI_dynstr_get_cstring(ds_failed_indices); + BLI_dynstr_free(ds_failed_indices); + + BKE_reportf(reports, + RPT_WARNING, + "Could not insert %i keyframe(s) due to zero NLA influence, base value, or value " + "remapping failed: %s.%s for indices [%s]", + total_failed, + ptr.owner_id->name, + RNA_property_ui_name(prop), + str_failed_indices); + + MEM_freeN(str_failed_indices); +} + /** * Retrieve current property values to keyframe, * possibly applying NLA correction when necessary. + * + * \param r_successful_remaps: Enables bits for indices which are both intended to be remapped and + * were successfully remapped. Bitmap allocated so it must be freed afterward. */ static float *get_keyframe_values(ReportList *reports, PointerRNA ptr, @@ -1121,8 +1175,10 @@ static float *get_keyframe_values(ReportList *reports, eInsertKeyFlags flag, float *buffer, int buffer_size, + const struct AnimationEvalContext *anim_eval_context, int *r_count, - bool *r_force_all) + bool *r_force_all, + BLI_bitmap **r_successful_remaps) { float *values; @@ -1138,17 +1194,25 @@ static float *get_keyframe_values(ReportList *reports, values = setting_get_rna_values(&ptr, prop, 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"); + *r_successful_remaps = BLI_BITMAP_NEW(*r_count, __func__); - if (values != buffer) { - MEM_freeN(values); - } - return NULL; - } + /* adjust the value for NLA factors */ + BKE_animsys_nla_remap_keyframe_values(nla_context, + &ptr, + prop, + values, + *r_count, + index, + anim_eval_context, + r_force_all, + *r_successful_remaps); + get_keyframe_values_create_reports(reports, + ptr, + prop, + index, + *r_count, + r_force_all ? *r_force_all : false, + *r_successful_remaps); return values; } @@ -1284,6 +1348,7 @@ bool insert_keyframe_direct(ReportList *reports, int value_count; int index = fcu->array_index; + BLI_bitmap *successful_remaps = NULL; float *values = get_keyframe_values(reports, ptr, prop, @@ -1292,13 +1357,10 @@ bool insert_keyframe_direct(ReportList *reports, flag, value_buffer, RNA_MAX_ARRAY_LENGTH, + anim_eval_context, &value_count, - NULL); - - if (values == NULL) { - /* This happens if NLA rejects this insertion. */ - return false; - } + NULL, + &successful_remaps); if (index >= 0 && index < value_count) { curval = values[index]; @@ -1308,6 +1370,14 @@ bool insert_keyframe_direct(ReportList *reports, MEM_freeN(values); } + const bool curval_valid = BLI_BITMAP_TEST_BOOL(successful_remaps, index); + MEM_freeN(successful_remaps); + + /* This happens if NLA rejects this insertion. */ + if (!curval_valid) { + return false; + } + return insert_keyframe_value(reports, &ptr, prop, fcu, anim_eval_context, curval, keytype, flag); } @@ -1461,6 +1531,7 @@ int insert_keyframe(Main *bmain, int value_count; bool force_all; + BLI_bitmap *successful_remaps = NULL; float *values = get_keyframe_values(reports, ptr, prop, @@ -1469,77 +1540,72 @@ int insert_keyframe(Main *bmain, flag, value_buffer, RNA_MAX_ARRAY_LENGTH, + anim_eval_context, &value_count, - &force_all); + &force_all, + &successful_remaps); - 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 | INSERTKEY_AVAILABLE)) != 0) { - int exclude = -1; + /* 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 | INSERTKEY_AVAILABLE)) != 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, - &remapped_context, - values[array_index], - keytype, - flag)) { - ret++; - exclude = array_index; - break; - } + for (array_index = 0; array_index < value_count; array_index++) { + if (!BLI_BITMAP_TEST_BOOL(successful_remaps, array_index)) { + continue; } - if (exclude != -1) { - flag &= ~(INSERTKEY_REPLACE | INSERTKEY_AVAILABLE); - - 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, - &remapped_context, - values[array_index], - keytype, - flag); - } - } + if (insert_keyframe_fcurve_value(bmain, + reports, + &ptr, + prop, + act, + group, + rna_path, + array_index, + &remapped_context, + values[array_index], + keytype, + flag)) { + ret++; + exclude = array_index; + break; } } - /* Simply insert all channels. */ - else { + + if (exclude != -1) { + flag &= ~(INSERTKEY_REPLACE | INSERTKEY_AVAILABLE); + 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, - &remapped_context, - values[array_index], - keytype, - flag); + if (!BLI_BITMAP_TEST_BOOL(successful_remaps, array_index)) { + continue; + } + + if (array_index != exclude) { + ret += insert_keyframe_fcurve_value(bmain, + reports, + &ptr, + prop, + act, + group, + rna_path, + array_index, + &remapped_context, + values[array_index], + keytype, + flag); + } } } } - /* Key a single index. */ + /* Simply insert all channels. */ else { - if (array_index >= 0 && array_index < value_count) { + for (array_index = 0; array_index < value_count; array_index++) { + if (!BLI_BITMAP_TEST_BOOL(successful_remaps, array_index)) { + continue; + } + ret += insert_keyframe_fcurve_value(bmain, reports, &ptr, @@ -1554,12 +1620,31 @@ int insert_keyframe(Main *bmain, flag); } } - - if (values != value_buffer) { - MEM_freeN(values); + } + /* Key a single index. */ + else { + if (array_index >= 0 && array_index < value_count && + BLI_BITMAP_TEST_BOOL(successful_remaps, array_index)) { + ret += insert_keyframe_fcurve_value(bmain, + reports, + &ptr, + prop, + act, + group, + rna_path, + array_index, + &remapped_context, + values[array_index], + keytype, + flag); } } + if (values != value_buffer) { + MEM_freeN(values); + } + + MEM_freeN(successful_remaps); BKE_animsys_free_nla_keyframing_context_cache(&tmp_nla_cache); if (ret) { @@ -1979,23 +2064,57 @@ static int insert_key_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UN { 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, WM_operatortype_name(op->type, op->ptr), ICON_NONE); - layout = UI_popup_menu_layout(pup); - uiItemsEnumO(layout, "ANIM_OT_keyframe_insert_menu", "type"); - UI_popup_menu_end(C, pup); + /* When there is an active keying set and no request to prompt, keyframe immediately. */ + if ((scene->active_keyingset != 0) && !RNA_boolean_get(op->ptr, "always_prompt")) { + /* Just call the exec() on the active keying-set. */ + RNA_enum_set(op->ptr, "type", 0); + return op->type->exec(C, op); + } + + /* Show a menu listing all keying-sets, the enum is expanded here to make use of the + * operator that accesses the keying-set by name. This is important for the ability + * to assign shortcuts to arbitrarily named keying sets. See T89560. + * These menu items perform the key-frame insertion (not this operator) + * hence the #OPERATOR_INTERFACE return. */ + uiPopupMenu *pup = UI_popup_menu_begin(C, WM_operatortype_name(op->type, op->ptr), ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); + + /* Even though `ANIM_OT_keyframe_insert_menu` can show a menu in one line, + * prefer `ANIM_OT_keyframe_insert_by_name` so users can bind keys to specific + * keying sets by name in the key-map instead of the index which isn't stable. */ + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type"); + const EnumPropertyItem *item_array = NULL; + int totitem; + bool free; + + RNA_property_enum_items_gettexted(C, op->ptr, prop, &item_array, &totitem, &free); + + for (int i = 0; i < totitem; i++) { + const EnumPropertyItem *item = &item_array[i]; + if (item->identifier[0] != '\0') { + uiItemStringO(layout, + item->name, + item->icon, + "ANIM_OT_keyframe_insert_by_name", + "type", + item->identifier); + } + else { + /* This enum shouldn't contain headings, assert there are none. + * NOTE: If in the future the enum includes them, additional layout code can be + * added to show them - although that doesn't seem likely. */ + BLI_assert(item->name == NULL); + uiItemS(layout); + } + } - return OPERATOR_INTERFACE; + if (free) { + MEM_freeN((void *)item_array); } - /* just call the exec() on the active keyingset */ - RNA_enum_set(op->ptr, "type", 0); - return op->type->exec(C, op); + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; } void ANIM_OT_keyframe_insert_menu(wmOperatorType *ot) |