Blender V5.0
keyframing_auto.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BKE_animsys.h"
10#include "BKE_context.hh"
11#include "BKE_fcurve.hh"
12#include "BKE_scene.hh"
13
14#include "DNA_scene_types.h"
15
16#include "RNA_access.hh"
17#include "RNA_path.hh"
18#include "RNA_prototypes.hh"
19
20#include "ANIM_keyframing.hh"
21#include "ANIM_keyingsets.hh"
22
23#include "WM_api.hh"
24#include "WM_types.hh"
25
26namespace blender::animrig {
27
29{
31
32 /* Visual keying. */
35 }
36
37 /* Only needed. */
40 }
41
42 /* Only insert available. */
45 }
46
47 /* Keyframing mode - only replace existing keyframes. */
50 }
51
52 /* Cycle-aware keyframe insertion - preserve cycle period and flow. */
55 }
56
57 return flag;
58}
59
60bool is_autokey_on(const Scene *scene)
61{
62 if (scene) {
63 return scene->toolsettings->autokey_mode & AUTOKEY_ON;
64 }
65 return U.autokey_mode & AUTOKEY_ON;
66}
67
68bool is_autokey_mode(const Scene *scene, const eAutokey_Mode mode)
69{
70 if (scene) {
71 return scene->toolsettings->autokey_mode == mode;
72 }
73 return U.autokey_mode == mode;
74}
75
76bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
77{
78 /* Only filter if auto-key mode requires this. */
79 if (!is_autokey_on(scene)) {
80 return false;
81 }
82
84 /* Replace Mode:
85 * For whole block, only key if there's a keyframe on that frame already
86 * This is a valid assumption when we're blocking + tweaking
87 */
88 const float cfra = BKE_scene_frame_get(scene);
89 return id_frame_has_keyframe(id, cfra);
90 }
91
92 /* Normal Mode (or treat as being normal mode):
93 *
94 * Just in case the flags aren't set properly (i.e. only on/off is set, without a mode)
95 * let's set the "normal" flag too, so that it will all be sane everywhere...
96 */
98
99 return true;
100}
101
102void autokeyframe_object(bContext *C, const Scene *scene, Object *ob, Span<RNAPath> rna_paths)
103{
104 BLI_assert(ob != nullptr);
105 BLI_assert(scene != nullptr);
106 BLI_assert(C != nullptr);
107
108 ID *id = &ob->id;
109 if (!autokeyframe_cfra_can_key(scene, id)) {
110 return;
111 }
112
113 ReportList *reports = CTX_wm_reports(C);
114 KeyingSet *active_ks = scene_get_active_keyingset(scene);
118
119 /* Get flags used for inserting keyframes. */
121
122 /* Add data-source override for the object. */
125
126 if (is_keying_flag(scene, AUTOKEY_FLAG_ONLYKEYINGSET) && (active_ks)) {
127 /* Only insert into active keyingset
128 * NOTE: we assume here that the active Keying Set
129 * does not need to have its iterator overridden.
130 */
131 apply_keyingset(C, &sources, active_ks, ModifyKeyMode::INSERT, anim_eval_context.eval_time);
132 return;
133 }
134
135 const float scene_frame = BKE_scene_frame_get(scene);
136 Main *bmain = CTX_data_main(C);
137
138 CombinedKeyingResult combined_result;
139 for (PointerRNA ptr : sources) {
141 bmain,
142 &ptr,
143 std::nullopt,
144 rna_paths,
145 scene_frame,
146 anim_eval_context,
148 flag);
149 combined_result.merge(result);
150 }
151
152 if (combined_result.get_count(SingleKeyingResult::SUCCESS) == 0) {
153 combined_result.generate_reports(reports);
154 }
155}
156
158{
159 if (!autokeyframe_cfra_can_key(scene, &ob->id)) {
160 return false;
161 }
162
163 /* Now insert the key-frame(s) using the Keying Set:
164 * 1) Add data-source override for the Object.
165 * 2) Insert key-frames.
166 * 3) Free the extra info.
167 */
169 relative_keyingset_add_source(sources, &ob->id);
171
172 return true;
173}
174
176{
177 if (!autokeyframe_cfra_can_key(scene, &ob->id)) {
178 return false;
179 }
180
181 /* Now insert the keyframe(s) using the Keying Set:
182 * 1) Add data-source override for the pose-channel.
183 * 2) Insert key-frames.
184 * 3) Free the extra info.
185 */
187 relative_keyingset_add_source(sources, &ob->id, &RNA_PoseBone, pchan);
189
190 return true;
191}
192
194 Scene *scene,
195 Object *ob,
196 bPoseChannel *pose_channel,
197 Span<RNAPath> rna_paths,
198 short targetless_ik)
199{
200 BLI_assert(C != nullptr);
201 BLI_assert(scene != nullptr);
202 BLI_assert(ob != nullptr);
203 BLI_assert(pose_channel != nullptr);
204
205 Main *bmain = CTX_data_main(C);
206 ID *id = &ob->id;
207
209 return;
210 }
211
212 ReportList *reports = CTX_wm_reports(C);
213 KeyingSet *active_ks = scene_get_active_keyingset(scene);
215 const float scene_frame = BKE_scene_frame_get(scene);
217 scene_frame);
218
219 /* flag is initialized from UserPref keyframing settings
220 * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get
221 * visual keyframes even if flag not set, as it's not that useful otherwise
222 * (for quick animation recording)
223 */
225
226 if (targetless_ik) {
228 }
229
230 Vector<PointerRNA> sources;
231 /* Add data-source override for the camera object. */
232 relative_keyingset_add_source(sources, id, &RNA_PoseBone, pose_channel);
233
234 /* only insert into active keyingset? */
235 if (is_keying_flag(scene, AUTOKEY_FLAG_ONLYKEYINGSET) && (active_ks)) {
236 /* Run the active Keying Set on the current data-source. */
237 apply_keyingset(C, &sources, active_ks, ModifyKeyMode::INSERT, anim_eval_context.eval_time);
238 return;
239 }
240
241 CombinedKeyingResult combined_result;
242 for (PointerRNA &ptr : sources) {
244 bmain,
245 &ptr,
246 std::nullopt,
247 rna_paths,
248 scene_frame,
249 anim_eval_context,
251 flag);
252 combined_result.merge(result);
253 }
254
255 if (combined_result.get_count(SingleKeyingResult::SUCCESS) == 0) {
256 combined_result.generate_reports(reports);
257 }
258}
259
261 Scene *scene,
263 PropertyRNA *prop,
264 const int rnaindex,
265 const float cfra,
266 const bool only_if_property_keyed)
267{
268
271 cfra);
272 bAction *action;
273 bool driven;
274 bool special;
275
276 /* For entire array buttons we check the first component, it's not perfect
277 * but works well enough in typical cases. */
278 const int rnaindex_check = (rnaindex == -1) ? 0 : rnaindex;
280 C, ptr, prop, rnaindex_check, nullptr, &action, &driven, &special);
281
282 /* Only early out when we actually want an existing F-curve already
283 * (e.g. auto-keyframing from buttons). */
284 if (fcu == nullptr && (driven || special || only_if_property_keyed)) {
285 return false;
286 }
287
288 if (driven) {
289 return false;
290 }
291
292 bool changed = false;
293 if (special) {
294 /* NLA Strip property. */
295 if (is_autokey_on(scene)) {
296 ReportList *reports = CTX_wm_reports(C);
297 ToolSettings *ts = scene->toolsettings;
298
299 changed = insert_keyframe_direct(reports,
300 *ptr,
301 prop,
302 fcu,
303 &anim_eval_context,
305 nullptr,
306 eInsertKeyFlags(0));
308 }
309 }
310 else {
311 ID *id = ptr->owner_id;
312 Main *bmain = CTX_data_main(C);
313
314 /* TODO: this should probably respect the keyingset only option for anim */
315 if (autokeyframe_cfra_can_key(scene, id)) {
316 ToolSettings *ts = scene->toolsettings;
318
319 if (only_if_property_keyed) {
320 /* NOTE: We use rnaindex instead of fcu->array_index,
321 * because a button may control all items of an array at once.
322 * E.g., color wheels (see #42567). */
323 BLI_assert((fcu->array_index == rnaindex) || (rnaindex == -1));
324 }
325
326 const std::optional<std::string> group = (fcu && fcu->grp) ? std::optional(fcu->grp->name) :
327 std::nullopt;
328 const std::string path = fcu ? fcu->rna_path :
329 RNA_path_from_ID_to_property(ptr, prop).value_or("");
330 /* NOTE: `rnaindex == -1` is a magic number, meaning either "operate on
331 * all elements" or "not an array property". */
332 const std::optional<int> array_index = rnaindex < 0 ? std::nullopt : std::optional(rnaindex);
333
334 PointerRNA id_pointer = RNA_id_pointer_create(ptr->owner_id);
336 &id_pointer,
337 group,
338 {{path, {}, array_index}},
339 std::nullopt,
340 anim_eval_context,
342 flag);
343 changed = result.get_count(SingleKeyingResult::SUCCESS) != 0;
345 }
346 }
347 return changed;
348}
349
350} // namespace blender::animrig
Functions to insert, delete or modify keyframes.
Functionality to interact with keying sets.
AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, float eval_time) ATTR_WARN_UNUSED_RESULT
Definition anim_sys.cc:738
ReportList * CTX_wm_reports(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Main * CTX_data_main(const bContext *C)
FCurve * BKE_fcurve_find_by_rna_context_ui(bContext *C, const PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **r_animdata, bAction **r_action, bool *r_driven, bool *r_special)
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2384
#define BLI_assert(a)
Definition BLI_assert.h:46
eInsertKeyFlags
@ INSERTKEY_CYCLE_AWARE
@ INSERTKEY_REPLACE
@ INSERTKEY_MATRIX
@ INSERTKEY_NEEDED
@ INSERTKEY_AVAILABLE
@ INSERTKEY_NOFLAGS
eBezTriple_KeyframeType
@ AUTOKEY_FLAG_INSERTNEEDED
@ KEYING_FLAG_VISUALKEY
@ KEYING_FLAG_CYCLEAWARE
@ AUTOKEY_FLAG_ONLYKEYINGSET
@ AUTOKEY_FLAG_INSERTAVAILABLE
eAutokey_Mode
@ AUTOKEY_MODE_NORMAL
@ AUTOKEY_MODE_EDITKEYS
@ AUTOKEY_ON
#define C
Definition RandGen.cpp:29
#define NC_ANIMATION
Definition WM_types.hh:388
#define NA_EDITED
Definition WM_types.hh:584
#define ND_KEYFRAME
Definition WM_types.hh:494
#define U
BPy_StructRNA * depsgraph
void merge(const CombinedKeyingResult &other)
int get_count(const SingleKeyingResult result) const
void generate_reports(ReportList *reports, eReportType report_level=RPT_ERROR)
bool is_autokey_on(const Scene *scene)
bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
void relative_keyingset_add_source(blender::Vector< PointerRNA > &sources, ID *id, StructRNA *srna, void *data)
KeyingSet * scene_get_active_keyingset(const Scene *scene)
bool is_autokey_mode(const Scene *scene, eAutokey_Mode mode)
bool id_frame_has_keyframe(ID *id, 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.
static eInsertKeyFlags get_autokey_flags(const Scene *scene)
bool autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel *pchan, KeyingSet *ks)
bool autokeyframe_property(bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra, bool only_if_property_keyed)
void autokeyframe_object(bContext *C, const Scene *scene, Object *ob, Span< RNAPath > rna_paths)
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)
void autokeyframe_pose_channel(bContext *C, Scene *scene, Object *ob, bPoseChannel *pose_channel, Span< RNAPath > rna_paths, short targetless_ik)
int apply_keyingset(bContext *C, blender::Vector< PointerRNA > *sources, KeyingSet *keyingset, ModifyKeyMode mode, float cfra)
PointerRNA RNA_id_pointer_create(ID *id)
std::optional< std::string > RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
Definition rna_path.cc:1173
bActionGroup * grp
char * rna_path
int array_index
Definition DNA_ID.h:414
struct ToolSettings * toolsettings
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4238
uint8_t flag
Definition wm_window.cc:145