1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 */
16
17 /** \file
18 * \ingroup pythonintern
19 *
20 * This file defines the animation related methods used in bpy_rna.c
21 */
22
23 #include <Python.h>
24 #include <float.h> /* FLT_MAX */
25
26 #include "MEM_guardedalloc.h"
27
28 #include "BLI_string.h"
29 #include "BLI_string_utils.h"
30 #include "BLI_utildefines.h"
31
32 #include "DNA_anim_types.h"
33 #include "DNA_scene_types.h"
34
35 #include "ED_keyframes_edit.h"
36 #include "ED_keyframing.h"
37
38 #include "BKE_anim_data.h"
39 #include "BKE_animsys.h"
40 #include "BKE_context.h"
41 #include "BKE_fcurve.h"
42 #include "BKE_global.h"
43 #include "BKE_idtype.h"
44 #include "BKE_lib_id.h"
45 #include "BKE_report.h"
46
47 #include "RNA_access.h"
48 #include "RNA_enum_types.h"
49
50 #include "WM_api.h"
51 #include "WM_types.h"
52
53 #include "bpy_capi_utils.h"
54 #include "bpy_rna.h"
55 #include "bpy_rna_anim.h"
56
57 #include "../generic/python_utildefines.h"
58
59 #include "DEG_depsgraph_build.h"
60
61 /* for keyframes and drivers */
pyrna_struct_anim_args_parse_ex(PointerRNA * ptr,const char * error_prefix,const char * path,const char ** r_path_full,int * r_index,bool * r_path_no_validate)62 static int pyrna_struct_anim_args_parse_ex(PointerRNA *ptr,
63 const char *error_prefix,
64 const char *path,
65 const char **r_path_full,
66 int *r_index,
67 bool *r_path_no_validate)
68 {
69 const bool is_idbase = RNA_struct_is_ID(ptr->type);
70 PropertyRNA *prop;
71 PointerRNA r_ptr;
72
73 if (ptr->data == NULL) {
74 PyErr_Format(
75 PyExc_TypeError, "%.200s this struct has no data, can't be animated", error_prefix);
76 return -1;
77 }
78
79 /* full paths can only be given from ID base */
80 if (is_idbase) {
81 int path_index = -1;
82 if (RNA_path_resolve_property_full(ptr, path, &r_ptr, &prop, &path_index) == false) {
83 prop = NULL;
84 }
85 else if (path_index != -1) {
86 PyErr_Format(PyExc_ValueError,
87 "%.200s path includes index, must be a separate argument",
88 error_prefix,
89 path);
90 return -1;
91 }
92 else if (ptr->owner_id != r_ptr.owner_id) {
93 PyErr_Format(PyExc_ValueError, "%.200s path spans ID blocks", error_prefix, path);
94 return -1;
95 }
96 }
97 else {
98 prop = RNA_struct_find_property(ptr, path);
99 r_ptr = *ptr;
100 }
101
102 if (prop == NULL) {
103 if (r_path_no_validate) {
104 *r_path_no_validate = true;
105 return -1;
106 }
107 PyErr_Format(PyExc_TypeError, "%.200s property \"%s\" not found", error_prefix, path);
108 return -1;
109 }
110
111 if (r_path_no_validate) {
112 /* Don't touch the index. */
113 }
114 else {
115 if (!RNA_property_animateable(&r_ptr, prop)) {
116 PyErr_Format(PyExc_TypeError, "%.200s property \"%s\" not animatable", error_prefix, path);
117 return -1;
118 }
119
120 if (RNA_property_array_check(prop) == 0) {
121 if ((*r_index) == -1) {
122 *r_index = 0;
123 }
124 else {
125 PyErr_Format(PyExc_TypeError,
126 "%.200s index %d was given while property \"%s\" is not an array",
127 error_prefix,
128 *r_index,
129 path);
130 return -1;
131 }
132 }
133 else {
134 const int array_len = RNA_property_array_length(&r_ptr, prop);
135 if ((*r_index) < -1 || (*r_index) >= array_len) {
136 PyErr_Format(PyExc_TypeError,
137 "%.200s index out of range \"%s\", given %d, array length is %d",
138 error_prefix,
139 path,
140 *r_index,
141 array_len);
142 return -1;
143 }
144 }
145 }
146
147 if (is_idbase) {
148 *r_path_full = BLI_strdup(path);
149 }
150 else {
151 *r_path_full = RNA_path_from_ID_to_property(&r_ptr, prop);
152
153 if (*r_path_full == NULL) {
154 PyErr_Format(PyExc_TypeError, "%.200s could not make path to \"%s\"", error_prefix, path);
155 return -1;
156 }
157 }
158
159 return 0;
160 }
161
pyrna_struct_anim_args_parse(PointerRNA * ptr,const char * error_prefix,const char * path,const char ** r_path_full,int * r_index)162 static int pyrna_struct_anim_args_parse(PointerRNA *ptr,
163 const char *error_prefix,
164 const char *path,
165 const char **r_path_full,
166 int *r_index)
167 {
168 return pyrna_struct_anim_args_parse_ex(ptr, error_prefix, path, r_path_full, r_index, NULL);
169 }
170
171 /**
172 * Unlike #pyrna_struct_anim_args_parse \a r_path_full may be copied from \a path.
173 */
pyrna_struct_anim_args_parse_no_resolve(PointerRNA * ptr,const char * error_prefix,const char * path,const char ** r_path_full)174 static int pyrna_struct_anim_args_parse_no_resolve(PointerRNA *ptr,
175 const char *error_prefix,
176 const char *path,
177 const char **r_path_full)
178 {
179 const bool is_idbase = RNA_struct_is_ID(ptr->type);
180 if (is_idbase) {
181 *r_path_full = path;
182 return 0;
183 }
184
185 char *path_prefix = RNA_path_from_ID_to_struct(ptr);
186 if (path_prefix == NULL) {
187 PyErr_Format(PyExc_TypeError,
188 "%.200s could not make path for type %s",
189 error_prefix,
190 RNA_struct_identifier(ptr->type));
191 return -1;
192 }
193
194 if (*path == '[') {
195 *r_path_full = BLI_string_joinN(path_prefix, path);
196 }
197 else {
198 *r_path_full = BLI_string_join_by_sep_charN('.', path_prefix, path);
199 }
200 MEM_freeN(path_prefix);
201
202 return 0;
203 }
204
pyrna_struct_anim_args_parse_no_resolve_fallback(PointerRNA * ptr,const char * error_prefix,const char * path,const char ** r_path_full,int * r_index)205 static int pyrna_struct_anim_args_parse_no_resolve_fallback(PointerRNA *ptr,
206 const char *error_prefix,
207 const char *path,
208 const char **r_path_full,
209 int *r_index)
210 {
211 bool path_unresolved = false;
212 if (pyrna_struct_anim_args_parse_ex(
213 ptr, error_prefix, path, r_path_full, r_index, &path_unresolved) == -1) {
214 if (path_unresolved == true) {
215 if (pyrna_struct_anim_args_parse_no_resolve(ptr, error_prefix, path, r_path_full) == -1) {
216 return -1;
217 }
218 }
219 else {
220 return -1;
221 }
222 }
223 return 0;
224 }
225
226 /* internal use for insert and delete */
pyrna_struct_keyframe_parse(PointerRNA * ptr,PyObject * args,PyObject * kw,const char * parse_str,const char * error_prefix,const char ** r_path_full,int * r_index,float * r_cfra,const char ** r_group_name,int * r_options)227 static int pyrna_struct_keyframe_parse(PointerRNA *ptr,
228 PyObject *args,
229 PyObject *kw,
230 const char *parse_str,
231 const char *error_prefix,
232 /* return values */
233 const char **r_path_full,
234 int *r_index,
235 float *r_cfra,
236 const char **r_group_name,
237 int *r_options)
238 {
239 static const char *kwlist[] = {"data_path", "index", "frame", "group", "options", NULL};
240 PyObject *pyoptions = NULL;
241 const char *path;
242
243 /* note, parse_str MUST start with 's|ifsO!' */
244 if (!PyArg_ParseTupleAndKeywords(args,
245 kw,
246 parse_str,
247 (char **)kwlist,
248 &path,
249 r_index,
250 r_cfra,
251 r_group_name,
252 &PySet_Type,
253 &pyoptions)) {
254 return -1;
255 }
256
257 if (pyrna_struct_anim_args_parse(ptr, error_prefix, path, r_path_full, r_index) == -1) {
258 return -1;
259 }
260
261 if (*r_cfra == FLT_MAX) {
262 *r_cfra = CTX_data_scene(BPY_context_get())->r.cfra;
263 }
264
265 /* flag may be null (no option currently for remove keyframes e.g.). */
266 if (r_options) {
267 if (pyoptions &&
268 (pyrna_set_to_enum_bitfield(
269 rna_enum_keying_flag_items_api, pyoptions, r_options, error_prefix) == -1)) {
270 return -1;
271 }
272
273 *r_options |= INSERTKEY_NO_USERPREF;
274 }
275
276 return 0; /* success */
277 }
278
279 char pyrna_struct_keyframe_insert_doc[] =
280 ".. method:: keyframe_insert(data_path, index=-1, frame=bpy.context.scene.frame_current, "
281 "group=\"\", options=set())\n"
282 "\n"
283 " Insert a keyframe on the property given, adding fcurves and animation data when "
284 "necessary.\n"
285 "\n"
286 " :arg data_path: path to the property to key, analogous to the fcurve's data path.\n"
287 " :type data_path: string\n"
288 " :arg index: array index of the property to key.\n"
289 " Defaults to -1 which will key all indices or a single channel if the property is not "
290 "an array.\n"
291 " :type index: int\n"
292 " :arg frame: The frame on which the keyframe is inserted, defaulting to the current "
293 "frame.\n"
294 " :type frame: float\n"
295 " :arg group: The name of the group the F-Curve should be added to if it doesn't exist "
296 "yet.\n"
297 " :type group: str\n"
298 " :arg options: Optional set of flags:\n"
299 "\n"
300 " - ``INSERTKEY_NEEDED`` Only insert keyframes where they're needed in the relevant "
301 "F-Curves.\n"
302 " - ``INSERTKEY_VISUAL`` Insert keyframes based on 'visual transforms'.\n"
303 " - ``INSERTKEY_XYZ_TO_RGB`` Color for newly added transformation F-Curves (Location, "
304 "Rotation, Scale) is based on the transform axis.\n"
305 " - ``INSERTKEY_REPLACE`` Only replace already existing keyframes.\n"
306 " - ``INSERTKEY_AVAILABLE`` Only insert into already existing F-Curves.\n"
307 " - ``INSERTKEY_CYCLE_AWARE`` Take cyclic extrapolation into account "
308 "(Cycle-Aware Keying option).\n"
309 " :type flag: set\n"
310 " :return: Success of keyframe insertion.\n"
311 " :rtype: boolean\n";
pyrna_struct_keyframe_insert(BPy_StructRNA * self,PyObject * args,PyObject * kw)312 PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyObject *kw)
313 {
314 /* args, pyrna_struct_keyframe_parse handles these */
315 const char *path_full = NULL;
316 int index = -1;
317 float cfra = FLT_MAX;
318 const char *group_name = NULL;
319 const char keytype = BEZT_KEYTYPE_KEYFRAME; /* XXX: Expose this as a one-off option... */
320 int options = 0;
321
322 PYRNA_STRUCT_CHECK_OBJ(self);
323
324 if (pyrna_struct_keyframe_parse(&self->ptr,
325 args,
326 kw,
327 "s|ifsO!:bpy_struct.keyframe_insert()",
328 "bpy_struct.keyframe_insert()",
329 &path_full,
330 &index,
331 &cfra,
332 &group_name,
333 &options) == -1) {
334 return NULL;
335 }
336
337 /* This assumes that keyframes are only added on original data & using the active depsgraph. If
338 * it turns out to be necessary for some reason to insert keyframes on evaluated objects, we can
339 * revisit this and add an explicit `depsgraph` keyword argument to the function call.
340 *
341 * It is unlikely that driver code (which is the reason this depsgraph pointer is obtained) will
342 * be executed from this function call, as this only happens when `options` has
343 * `INSERTKEY_DRIVER`, which is not exposed to Python. */
344 bContext *C = BPY_context_get();
345 struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
346 const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
347 cfra);
348
349 if (self->ptr.type == &RNA_NlaStrip) {
350 /* Handle special properties for NLA Strips, whose F-Curves are stored on the
351 * strips themselves. These are stored separately or else the properties will
352 * not have any effect.
353 */
354 ReportList reports;
355 bool result = false;
356
357 PointerRNA ptr = self->ptr;
358 PropertyRNA *prop = NULL;
359 const char *prop_name;
360
361 BKE_reports_init(&reports, RPT_STORE);
362
363 /* Retrieve the property identifier from the full path, since we can't get it any other way */
364 prop_name = strrchr(path_full, '.');
365 if ((prop_name >= path_full) && (prop_name + 1 < path_full + strlen(path_full))) {
366 prop = RNA_struct_find_property(&ptr, prop_name + 1);
367 }
368
369 if (prop) {
370 NlaStrip *strip = ptr.data;
371 FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
372 result = insert_keyframe_direct(
373 &reports, ptr, prop, fcu, &anim_eval_context, keytype, NULL, options);
374 }
375 else {
376 BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full);
377 }
378 MEM_freeN((void *)path_full);
379
380 if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
381 return NULL;
382 }
383
384 return PyBool_FromLong(result);
385 }
386
387 ID *id = self->ptr.owner_id;
388 ReportList reports;
389 bool result;
390
391 BKE_reports_init(&reports, RPT_STORE);
392
393 BLI_assert(BKE_id_is_in_global_main(id));
394 result = (insert_keyframe(G_MAIN,
395 &reports,
396 id,
397 NULL,
398 group_name,
399 path_full,
400 index,
401 &anim_eval_context,
402 keytype,
403 NULL,
404 options) != 0);
405 MEM_freeN((void *)path_full);
406
407 if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
408 return NULL;
409 }
410
411 return PyBool_FromLong(result);
412 }
413
414 char pyrna_struct_keyframe_delete_doc[] =
415 ".. method:: keyframe_delete(data_path, index=-1, frame=bpy.context.scene.frame_current, "
416 "group=\"\")\n"
417 "\n"
418 " Remove a keyframe from this properties fcurve.\n"
419 "\n"
420 " :arg data_path: path to the property to remove a key, analogous to the fcurve's data "
421 "path.\n"
422 " :type data_path: string\n"
423 " :arg index: array index of the property to remove a key. Defaults to -1 removing all "
424 "indices or a single channel if the property is not an array.\n"
425 " :type index: int\n"
426 " :arg frame: The frame on which the keyframe is deleted, defaulting to the current frame.\n"
427 " :type frame: float\n"
428 " :arg group: The name of the group the F-Curve should be added to if it doesn't exist "
429 "yet.\n"
430 " :type group: str\n"
431 " :return: Success of keyframe deletion.\n"
432 " :rtype: boolean\n";
pyrna_struct_keyframe_delete(BPy_StructRNA * self,PyObject * args,PyObject * kw)433 PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyObject *kw)
434 {
435 /* args, pyrna_struct_keyframe_parse handles these */
436 const char *path_full = NULL;
437 int index = -1;
438 float cfra = FLT_MAX;
439 const char *group_name = NULL;
440
441 PYRNA_STRUCT_CHECK_OBJ(self);
442
443 if (pyrna_struct_keyframe_parse(&self->ptr,
444 args,
445 kw,
446 "s|ifsO!:bpy_struct.keyframe_delete()",
447 "bpy_struct.keyframe_insert()",
448 &path_full,
449 &index,
450 &cfra,
451 &group_name,
452 NULL) == -1) {
453 return NULL;
454 }
455 if (self->ptr.type == &RNA_NlaStrip) {
456 /* Handle special properties for NLA Strips, whose F-Curves are stored on the
457 * strips themselves. These are stored separately or else the properties will
458 * not have any effect.
459 */
460 ReportList reports;
461 bool result = false;
462
463 PointerRNA ptr = self->ptr;
464 PropertyRNA *prop = NULL;
465 const char *prop_name;
466
467 BKE_reports_init(&reports, RPT_STORE);
468
469 /* Retrieve the property identifier from the full path, since we can't get it any other way */
470 prop_name = strrchr(path_full, '.');
471 if ((prop_name >= path_full) && (prop_name + 1 < path_full + strlen(path_full))) {
472 prop = RNA_struct_find_property(&ptr, prop_name + 1);
473 }
474
475 if (prop) {
476 ID *id = ptr.owner_id;
477 NlaStrip *strip = ptr.data;
478 FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
479
480 /* NOTE: This should be true, or else we wouldn't be able to get here. */
481 BLI_assert(fcu != NULL);
482
483 if (BKE_fcurve_is_protected(fcu)) {
484 BKE_reportf(
485 &reports,
486 RPT_WARNING,
487 "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'",
488 strip->name,
489 BKE_idtype_idcode_to_name(GS(id->name)),
490 id->name + 2);
491 }
492 else {
493 /* remove the keyframe directly
494 * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve,
495 * and delete_keyframe() expects the FCurve to be part of an action
496 */
497 bool found = false;
498 int i;
499
500 /* try to find index of beztriple to get rid of */
501 i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, cfra, fcu->totvert, &found);
502 if (found) {
503 /* delete the key at the index (will sanity check + do recalc afterwards) */
504 delete_fcurve_key(fcu, i, 1);
505 result = true;
506 }
507 }
508 }
509 else {
510 BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full);
511 }
512 MEM_freeN((void *)path_full);
513
514 if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
515 return NULL;
516 }
517
518 return PyBool_FromLong(result);
519 }
520
521 bool result;
522 ReportList reports;
523
524 BKE_reports_init(&reports, RPT_STORE);
525
526 result = (delete_keyframe(G.main, &reports, self->ptr.owner_id, NULL, path_full, index, cfra) !=
527 0);
528 MEM_freeN((void *)path_full);
529
530 if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
531 return NULL;
532 }
533
534 return PyBool_FromLong(result);
535 }
536
537 char pyrna_struct_driver_add_doc[] =
538 ".. method:: driver_add(path, index=-1)\n"
539 "\n"
540 " Adds driver(s) to the given property\n"
541 "\n"
542 " :arg path: path to the property to drive, analogous to the fcurve's data path.\n"
543 " :type path: string\n"
544 " :arg index: array index of the property drive. Defaults to -1 for all indices or a single "
545 "channel if the property is not an array.\n"
546 " :type index: int\n"
547 " :return: The driver(s) added.\n"
548 " :rtype: :class:`bpy.types.FCurve` or list if index is -1 with an array property.\n";
pyrna_struct_driver_add(BPy_StructRNA * self,PyObject * args)549 PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args)
550 {
551 const char *path, *path_full;
552 int index = -1;
553
554 PYRNA_STRUCT_CHECK_OBJ(self);
555
556 if (!PyArg_ParseTuple(args, "s|i:driver_add", &path, &index)) {
557 return NULL;
558 }
559
560 if (pyrna_struct_anim_args_parse(
561 &self->ptr, "bpy_struct.driver_add():", path, &path_full, &index) == -1) {
562 return NULL;
563 }
564
565 PyObject *ret = NULL;
566 ReportList reports;
567 int result;
568
569 BKE_reports_init(&reports, RPT_STORE);
570
571 result = ANIM_add_driver(&reports,
572 (ID *)self->ptr.owner_id,
573 path_full,
574 index,
575 CREATEDRIVER_WITH_FMODIFIER,
576 DRIVER_TYPE_PYTHON);
577
578 if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
579 return NULL;
580 }
581
582 if (result) {
583 ID *id = self->ptr.owner_id;
584 AnimData *adt = BKE_animdata_from_id(id);
585 FCurve *fcu;
586
587 PointerRNA tptr;
588
589 if (index == -1) { /* all, use a list */
590 int i = 0;
591 ret = PyList_New(0);
592 while ((fcu = BKE_fcurve_find(&adt->drivers, path_full, i++))) {
593 RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
594 PyList_APPEND(ret, pyrna_struct_CreatePyObject(&tptr));
595 }
596 }
597 else {
598 fcu = BKE_fcurve_find(&adt->drivers, path_full, index);
599 RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
600 ret = pyrna_struct_CreatePyObject(&tptr);
601 }
602
603 bContext *context = BPY_context_get();
604 WM_event_add_notifier(BPY_context_get(), NC_ANIMATION | ND_FCURVES_ORDER, NULL);
605 DEG_relations_tag_update(CTX_data_main(context));
606 }
607 else {
608 /* XXX, should be handled by reports, */
609 PyErr_SetString(PyExc_TypeError,
610 "bpy_struct.driver_add(): failed because of an internal error");
611 return NULL;
612 }
613
614 MEM_freeN((void *)path_full);
615
616 return ret;
617 }
618
619 char pyrna_struct_driver_remove_doc[] =
620 ".. method:: driver_remove(path, index=-1)\n"
621 "\n"
622 " Remove driver(s) from the given property\n"
623 "\n"
624 " :arg path: path to the property to drive, analogous to the fcurve's data path.\n"
625 " :type path: string\n"
626 " :arg index: array index of the property drive. Defaults to -1 for all indices or a single "
627 "channel if the property is not an array.\n"
628 " :type index: int\n"
629 " :return: Success of driver removal.\n"
630 " :rtype: boolean\n";
pyrna_struct_driver_remove(BPy_StructRNA * self,PyObject * args)631 PyObject *pyrna_struct_driver_remove(BPy_StructRNA *self, PyObject *args)
632 {
633 const char *path, *path_full;
634 int index = -1;
635
636 PYRNA_STRUCT_CHECK_OBJ(self);
637
638 if (!PyArg_ParseTuple(args, "s|i:driver_remove", &path, &index)) {
639 return NULL;
640 }
641
642 if (pyrna_struct_anim_args_parse_no_resolve_fallback(
643 &self->ptr, "bpy_struct.driver_remove():", path, &path_full, &index) == -1) {
644 return NULL;
645 }
646
647 short result;
648 ReportList reports;
649
650 BKE_reports_init(&reports, RPT_STORE);
651
652 result = ANIM_remove_driver(&reports, (ID *)self->ptr.owner_id, path_full, index, 0);
653
654 if (path != path_full) {
655 MEM_freeN((void *)path_full);
656 }
657
658 if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
659 return NULL;
660 }
661
662 bContext *context = BPY_context_get();
663 WM_event_add_notifier(context, NC_ANIMATION | ND_FCURVES_ORDER, NULL);
664 DEG_relations_tag_update(CTX_data_main(context));
665
666 return PyBool_FromLong(result);
667 }
668