12#include <fmt/format.h>
46#include "RNA_prototypes.hh"
54 result_counter.fill(0);
64 for (
int i = 0;
i < result_counter.size();
i++) {
65 result_counter[
i] += other.result_counter[
i];
71 return result_counter[int(
result)];
79 for (
int i = 1;
i < result_counter.size();
i++) {
80 if (result_counter[
i] > 0) {
91 reports,
RPT_WARNING,
"No keys have been inserted and no errors have been reported.");
99 fmt::runtime(
RPT_(
"There were {:d} keying failures for unknown reasons.")), error_count));
104 errors.
append(fmt::format(
105 fmt::runtime(
RPT_(
"Could not create {:d} F-Curve(s). This can happen when only "
106 "inserting to available F-Curves.")),
113 fmt::format(fmt::runtime(
RPT_(
114 "{:d} F-Curve(s) are not keyframeable. They might be locked or sampled.")),
120 errors.
append(fmt::format(
122 "Due to the setting 'Only Insert Needed', {:d} keyframe(s) have not been inserted.")),
128 errors.
append(fmt::format(
129 fmt::runtime(
RPT_(
"Due to the NLA stack setup, {:d} keyframe(s) have not been inserted.")),
135 errors.
append(fmt::format(
136 fmt::runtime(
RPT_(
"Inserting keys on {:d} data-block(s) has been skipped because "
137 "they are not editable.")),
143 errors.
append(fmt::format(
144 fmt::runtime(
RPT_(
"Inserting keys on {:d} data-block(s) has been skipped because "
145 "they cannot be animated.")),
151 errors.
append(fmt::format(
152 fmt::runtime(
RPT_(
"Inserting keys on {:d} data-block(s) has been skipped because "
153 "the RNA path wasn't valid for them.")),
159 errors.
append(fmt::format(
160 fmt::runtime(
RPT_(
"Inserting keys on {:d} data-block(s) has been skipped because "
161 "there were no layers that could accept the keys.")),
167 errors.
append(fmt::format(
168 fmt::runtime(
RPT_(
"Inserting keys on {:d} data-block(s) has been skipped because "
169 "there were no strips that could accept the keys.")),
175 errors.
append(fmt::format(
176 fmt::runtime(
RPT_(
"Inserting keys on {:d} data-block(s) has been skipped because "
177 "of missing action slots.")),
186 if (errors.
size() == 1) {
187 BKE_report(reports, report_level, errors[0].c_str());
191 std::string error_message =
RPT_(
"Inserting keyframes failed:");
192 for (
const std::string &
error : errors) {
193 error_message.append(fmt::format(
"\n- {}",
error));
195 BKE_report(reports, report_level, error_message.c_str());
201 if (animated_struct->
type == &RNA_PoseBone) {
203 return pose_channel->
name;
206 if (animated_struct->
type == &RNA_Object) {
214 return "Object Transforms";
234 return U.keying_flag &
flag;
267 if (adt.
action ==
nullptr) {
346 const float period = action_range[1] - action_range[0];
353 const float frame_offset = fcu->
bezt[0].
vec[1][0] - action_range[0];
354 const float fix =
floorf(frame_offset / period) * period;
365 fcu->
bezt[1].
vec[0][0] += period;
366 fcu->
bezt[1].
vec[1][0] += period;
367 fcu->
bezt[1].
vec[2][0] += period;
380 const bool force_all,
381 const BitSpan successful_remaps)
386 int total_failed = 0;
388 const bool cur_index_evaluated =
ELEM(index,
i, -1) || force_all;
389 if (!cur_index_evaluated) {
394 if (successful_remaps[
i]) {
404 if (total_failed == 0) {
414 "Could not insert %i keyframe(s) due to zero NLA influence, base value, or value "
415 "remapping failed: %s.%s for indices [%s]",
452 nla_context, &
ptr, &prop, values, index, anim_eval_context, force_all, successful_remaps);
454 reports,
ptr, &prop, index, values.
size(),
false, successful_remaps);
455 return successful_remaps;
466 if (adt && adt->
action == act) {
468 nla_cache, id_ptr, adt, anim_eval_context);
471 return remapped_frame;
474 *r_nla_context =
nullptr;
502 if (fcu ==
nullptr) {
507 if ((
ptr.owner_id ==
nullptr) && (
ptr.data ==
nullptr)) {
509 reports,
RPT_ERROR,
"No RNA pointer available to retrieve values for keyframing from");
513 if (prop ==
nullptr) {
517 const char *idname = (
ptr.owner_id) ?
ptr.owner_id->name :
RPT_(
"<No ID pointer>");
521 "Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, "
549 float current_value = 0.0f;
550 if (index >= 0 && index < values.
size()) {
551 current_value = values[index];
555 if (!successful_remaps[index]) {
559 const float cfra = anim_eval_context->
eval_time;
565 "Failed to insert keys on F-Curve with path '%s[%d]', ensure that it is not "
566 "locked or sampled, and try removing F-Modifiers",
579 const char rna_path[],
581 const float fcurve_frame,
602 const bool is_new_curve = (fcu->
totvert == 0);
607 if (is_cyclic_action && fcu->
totvert == 1) {
615 fcu, fcurve_frame, curval, keytype,
flag);
618 if (is_cyclic_action && is_new_curve) {
638 if (adt->
action ==
nullptr) {
654 if (
ELEM(
nullptr,
id, adt)) {
666 "Could not delete keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)",
668 rna_path.
path.c_str());
678 int array_index = rna_path.
index.value_or(0);
679 int array_index_max = array_index + 1;
681 if (!rna_path.
index.has_value()) {
687 if (array_index_max == array_index) {
692 Action &action = act->wrap();
704 for (; array_index < array_index_max; array_index++) {
706 if (fcurve ==
nullptr) {
710 modified_fcurves.
append(fcurve);
716 for (; array_index < array_index_max; array_index++) {
719 if (fcu ==
nullptr) {
726 "Not deleting keyframe for locked F-Curve '%s' for %s '%s'",
734 modified_fcurves.
append(fcu);
740 for (
FCurve *fcurve : modified_fcurves) {
748 return modified_fcurves.
size();
758 if (
ELEM(
nullptr,
id, adt)) {
770 "Could not clear keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)",
772 rna_path.
path.c_str());
782 Action &action = act->wrap();
789 if (rna_path.index.has_value() && rna_path.index.value() != fcurve.array_index) {
798 for (
FCurve *fcu : fcurves) {
806 int array_index = rna_path.index.value_or(0);
807 int array_index_max = array_index + 1;
808 if (!rna_path.index.has_value()) {
815 if (array_index_max == array_index) {
820 for (; array_index < array_index_max; array_index++) {
823 if (fcu ==
nullptr) {
830 "Not clearing all keyframes from locked F-Curve '%s' for %s '%s'",
855 const std::optional<StringRefNull> channel_group,
856 const std::string &rna_path,
865 BLI_assert(action->wrap().is_action_legacy());
868 if (channel_group.has_value()) {
869 group = channel_group->c_str();
874 group = default_group.has_value() ? default_group->c_str() :
nullptr;
877 int property_array_index = 0;
879 for (
float value : values) {
880 if (!keying_mask[property_array_index]) {
882 property_array_index++;
891 property_array_index,
896 combined_result.
add(keying_result);
897 property_array_index++;
899 return combined_result;
912 const std::string &rna_path,
914 const std::optional<blender::StringRefNull> channel_group,
931 {rna_path, key_data.
array_index, prop_type, prop_subtype, channel_group},
943 "The animated ID should not be using another Action than the one passed to this function");
948 "The conditions that would cause this Slot assignment to fail (such as the ID not being "
949 "animatible) should have been caught and handled by higher-level functions.");
961 return std::make_pair(layer, slot);
970 const std::optional<StringRefNull> channel_group,
971 const std::string &rna_path,
981 int property_array_index = 0;
983 for (
float value : values) {
984 if (!keying_mask[property_array_index]) {
986 property_array_index++;
989 const KeyInsertData key_data = {{frame, value}, property_array_index};
1002 property_array_index++;
1004 return combined_result;
1009 const std::optional<StringRefNull> channel_group,
1011 const std::optional<float> scene_frame,
1023 if (adt ==
nullptr) {
1025 return combined_result;
1030 return combined_result;
1036 return combined_result;
1042 Action &action = dna_action->wrap();
1050 ListBase nla_cache = {
nullptr,
nullptr};
1061 for (
const RNAPath &rna_path : rna_paths) {
1065 struct_pointer, rna_path.path.c_str(), &
ptr, &prop);
1066 if (!path_resolved) {
1081 rna_path.index.value_or(-1),
1087 if (!rna_path_id_to_prop.has_value()) {
1090 if (struct_pointer->
data !=
id) {
1095 rna_path_id_to_prop = rna_path.path;
1111 bool at_least_one_would_succeed =
false;
1112 for (
int i = 0;
i < rna_values.
size();
i++) {
1121 at_least_one_would_succeed =
true;
1130 at_least_one_would_succeed =
true;
1137 if (at_least_one_would_succeed) {
1143 if (is_action_legacy) {
1149 *rna_path_id_to_prop,
1152 insert_key_flags_adjusted,
1161 const std::optional<blender::StringRefNull> this_rna_path_channel_group =
1162 channel_group.has_value() ? *channel_group :
1170 this_rna_path_channel_group,
1171 *rna_path_id_to_prop,
1203 if (!
ELEM(adt->
action,
nullptr, dna_action)) {
1208 return combined_result;
Functions and classes to work with Actions.
Functionality to iterate an Action in various ways.
Functions for backward compatibility with the legacy Action API.
Functions to work with AnimData.
Functions to modify FCurves.
Functions to insert, delete or modify keyframes.
Helper functions for animation to interact with the RNA system.
Functions to work with the visual keying system.
Blender kernel action and pose functionality.
AnimData * BKE_animdata_ensure_id(ID *id)
AnimData * BKE_animdata_from_id(const ID *id)
void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache)
void BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context, struct PointerRNA *prop_ptr, struct PropertyRNA *prop, const blender::MutableSpan< float > values, int index, const struct AnimationEvalContext *anim_eval_context, bool *r_force_all, blender::BitVector<> &r_values_mask)
struct NlaKeyframingContext * BKE_animsys_get_nla_keyframing_context(struct ListBase *cache, struct PointerRNA *ptr, struct AnimData *adt, const struct AnimationEvalContext *anim_eval_context)
bool BKE_fcurve_is_keyframable(const FCurve *fcu)
int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[], float frame, int arraylen, bool *r_replace)
FModifier * add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
bool BKE_fcurve_is_empty(const FCurve *fcu)
bool BKE_fcurve_is_protected(const FCurve *fcu)
const char * BKE_idtype_idcode_to_name(short idcode)
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, eNlaTime_ConvertModes mode)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
#define BLI_assert_msg(a, msg)
A dynamically sized string ADT.
char * BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_ANIMATION_NO_FLUSH
#define ID_IS_LINKED(_id)
#define ID_IS_OVERRIDE_LIBRARY(_id)
@ MANUALKEY_FLAG_INSERTNEEDED
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
constexpr int64_t size() const
constexpr int64_t size() const
static constexpr int64_t not_found
constexpr int64_t find(char c, int64_t pos=0) const
void append(const T &value)
MutableSpan< T > as_mutable_span()
Span< T > as_span() const
void layer_keystrip_ensure()
float2 get_frame_range() const ATTR_WARN_UNUSED_RESULT
bool is_cyclic() const ATTR_WARN_UNUSED_RESULT
Layer * get_layer_for_keyframing()
bool is_action_layered() const
Slot * slot_for_handle(slot_handle_t handle)
void merge(const CombinedKeyingResult &other)
int get_count(const SingleKeyingResult result) const
void generate_reports(ReportList *reports, eReportType report_level=RPT_ERROR)
void add(SingleKeyingResult result, int count=1)
blender::Span< const Strip * > strips() const
const Strip * strip(int64_t index) const
const T & data(const Action &owning_action) const
DEG_id_tag_update_ex(cb_data->bmain, cb_data->owner_id, ID_RECALC_TAG_FOR_UNDO|ID_RECALC_SYNC_TO_EVAL)
void MEM_freeN(void *vmemh)
static void error(const char *str)
Vector< FCurve * > fcurves_for_assigned_action(AnimData *adt)
bool action_treat_as_legacy(const bAction &action)
void foreach_fcurve_in_action_slot(Action &action, slot_handle_t handle, FunctionRef< void(FCurve &fcurve)> callback)
bool action_fcurve_remove(Action &action, FCurve &fcu)
void assert_baklava_phase_1_invariants(const Action &action)
std::optional< StringRefNull > default_channel_group_for_path(const PointerRNA *animated_struct, StringRef prop_rna_path)
static Vector< float > get_keyframe_values(PointerRNA *ptr, PropertyRNA *prop, const bool visual_key)
void animdata_fcurve_delete(AnimData *adt, FCurve *fcu)
KeyframeSettings get_keyframe_settings(bool from_userprefs)
Slot * assign_action_ensure_slot_for_keying(Action &action, ID &animated_id)
static bool object_frame_has_keyframe(Object *ob, const float frame)
bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame)
bAction * id_action_ensure(Main *bmain, ID *id)
eFCurve_Flags fcurve_flags_for_property_type(PropertyType prop_type)
Vector< float > visualkey_get_values(PointerRNA *ptr, PropertyRNA *prop)
bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
static SingleKeyingResult insert_key_layer(Main *bmain, Action &action, Layer &layer, const Slot &slot, const std::string &rna_path, PropertyRNA *prop, const std::optional< blender::StringRefNull > channel_group, const KeyInsertData &key_data, const KeyframeSettings &key_settings, const eInsertKeyFlags insert_key_flags)
void update_autoflags_fcurve_direct(FCurve *fcu, PropertyType prop_type)
static SingleKeyingResult insert_keyframe_value(FCurve *fcu, float cfra, float curval, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag)
static CombinedKeyingResult insert_key_legacy_action(Main *bmain, bAction *action, PointerRNA *ptr, PropertyRNA *prop, const std::optional< StringRefNull > channel_group, const std::string &rna_path, const float frame, const Span< float > values, eInsertKeyFlags insert_key_flag, eBezTriple_KeyframeType key_type, const BitSpan keying_mask)
Vector< float > get_rna_values(PointerRNA *ptr, PropertyRNA *prop)
static void get_keyframe_values_create_reports(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, const int index, const int count, const bool force_all, const BitSpan successful_remaps)
int clear_keyframe(Main *bmain, ReportList *reports, ID *id, const RNAPath &rna_path)
int delete_keyframe(Main *bmain, ReportList *reports, ID *id, const RNAPath &rna_path, float cfra)
Main Delete Key-Framing API call.
bool fcurve_delete_keyframe_at_time(FCurve *fcurve, float time)
bool id_frame_has_keyframe(ID *id, float frame)
static bool assigned_action_has_keyframe_at(AnimData &adt, const float frame)
CombinedKeyingResult insert_keyframes(Main *bmain, PointerRNA *struct_pointer, std::optional< StringRefNull > channel_group, const blender::Span< RNAPath > rna_paths, std::optional< float > scene_frame, const AnimationEvalContext &anim_eval_context, eBezTriple_KeyframeType key_type, eInsertKeyFlags insert_key_flags)
Main key-frame insertion API.
SingleKeyingResult insert_vert_fcurve(FCurve *fcu, const float2 position, const KeyframeSettings &settings, eInsertKeyFlags flag)
Main Key-framing API call.
Span< FCurve * > fcurves_for_action_slot(Action &action, slot_handle_t slot_handle)
const FCurve * fcurve_find(Span< const FCurve * > fcurves, const FCurveDescriptor &fcurve_descriptor)
static void make_new_fcurve_cyclic(FCurve *fcu, const blender::float2 &action_range)
Action * get_action(ID &animated_id)
FCurve * action_fcurve_ensure_ex(Main *bmain, bAction *act, const char group[], PointerRNA *ptr, const FCurveDescriptor &fcurve_descriptor)
static CombinedKeyingResult insert_key_layered_action(Main *bmain, Action &action, Layer &layer, const Slot &slot, PropertyRNA *prop, const std::optional< StringRefNull > channel_group, const std::string &rna_path, const float frame, const Span< float > values, const eInsertKeyFlags insert_key_flags, const KeyframeSettings &key_settings, const BitSpan keying_mask)
static BitVector nla_map_keyframe_values_and_generate_reports(const MutableSpan< float > values, const int index, PointerRNA &ptr, PropertyRNA &prop, NlaKeyframingContext *nla_context, const AnimationEvalContext *anim_eval_context, ReportList *reports, bool *force_all)
static float nla_time_remap(float time, const AnimationEvalContext *anim_eval_context, PointerRNA *id_ptr, AnimData *adt, bAction *act, ListBase *nla_cache, NlaKeyframingContext **r_nla_context)
bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, const AnimationEvalContext *anim_eval_context, eBezTriple_KeyframeType keytype, NlaKeyframingContext *nla_context, eInsertKeyFlags flag)
Secondary Insert Key-framing API call.
bool is_keying_flag(const Scene *scene, eKeying_Flag flag)
static std::pair< Layer *, Slot * > prep_action_layer_for_keying(Action &action, ID &animated_id)
bool key_insertion_may_create_fcurve(eInsertKeyFlags insert_key_flags)
static SingleKeyingResult insert_keyframe_fcurve_value(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, bAction *act, const char group[], const char rna_path[], int array_index, const float fcurve_frame, float curval, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag)
FCurve * fcurve_find_in_action(bAction *act, const FCurveDescriptor &fcurve_descriptor)
static void deg_tag_after_keyframe_delete(Main *bmain, ID *id, AnimData *adt)
eInsertKeyFlags get_keyframing_flags(Scene *scene)
@ UNABLE_TO_INSERT_TO_NLA_STACK
@ FCURVE_NOT_KEYFRAMEABLE
VecBase< float, 2 > float2
PropertyType RNA_property_type(PropertyRNA *prop)
const char * RNA_property_ui_name(const PropertyRNA *prop, const PointerRNA *ptr)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
PropertySubType RNA_property_subtype(PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
std::optional< std::string > RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
std::optional< int > index
struct ToolSettings * toolsettings
eBezTriple_KeyframeType keyframe_type