2011-03-02 04:51:43 +00:00
|
|
|
/*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
* \ingroup pythonintern
|
2011-11-05 08:21:12 +00:00
|
|
|
*
|
|
|
|
* This file defines the animation related methods used in bpy_rna.c
|
2011-03-02 04:51:43 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <Python.h>
|
2016-05-11 21:36:42 +10:00
|
|
|
#include <float.h> /* FLT_MAX */
|
2011-03-02 04:51:43 +00:00
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "BLI_string.h"
|
2019-01-07 15:27:59 +11:00
|
|
|
#include "BLI_string_utils.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_utildefines.h"
|
2011-03-02 04:51:43 +00:00
|
|
|
|
|
|
|
#include "DNA_anim_types.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_scene_types.h"
|
2016-12-28 23:27:46 +13:00
|
|
|
|
|
|
|
#include "ED_keyframes_edit.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "ED_keyframing.h"
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2020-04-03 13:07:36 +02:00
|
|
|
#include "BKE_anim_data.h"
|
T77086 Animation: Passing Dependency Graph to Drivers
Custom driver functions need access to the dependency graph that is
triggering the evaluation of the driver. This patch passes the
dependency graph pointer through all the animation-related calls.
Instead of passing the evaluation time to functions, the code now passes
an `AnimationEvalContext` pointer:
```
typedef struct AnimationEvalContext {
struct Depsgraph *const depsgraph;
const float eval_time;
} AnimationEvalContext;
```
These structs are read-only, meaning that the code cannot change the
evaluation time. Note that the `depsgraph` pointer itself is const, but
it points to a non-const depsgraph.
FCurves and Drivers can be evaluated at a different time than the
current scene time, for example when evaluating NLA strips. This means
that, even though the current time is stored in the dependency graph, we
need an explicit evaluation time.
There are two functions that allow creation of `AnimationEvalContext`
objects:
- `BKE_animsys_eval_context_construct(Depsgraph *depsgraph, float
eval_time)`, which creates a new context object from scratch, and
- `BKE_animsys_eval_context_construct_at(AnimationEvalContext
*anim_eval_context, float eval_time)`, which can be used to create a
`AnimationEvalContext` with the same depsgraph, but at a different
time. This makes it possible to later add fields without changing any
of the code that just want to change the eval time.
This also provides a fix for T75553, although it does require a change
to the custom driver function. The driver should call
`custom_function(depsgraph)`, and the function should use that depsgraph
instead of information from `bpy.context`.
Reviewed By: brecht, sergey
Differential Revision: https://developer.blender.org/D8047
2020-07-17 17:38:09 +02:00
|
|
|
#include "BKE_animsys.h"
|
2018-06-07 12:47:00 +02:00
|
|
|
#include "BKE_context.h"
|
2011-03-02 04:51:43 +00:00
|
|
|
#include "BKE_fcurve.h"
|
2018-06-07 12:47:00 +02:00
|
|
|
#include "BKE_global.h"
|
2020-03-19 19:37:00 +01:00
|
|
|
#include "BKE_idtype.h"
|
2020-02-10 12:58:59 +01:00
|
|
|
#include "BKE_lib_id.h"
|
2018-06-07 12:47:00 +02:00
|
|
|
#include "BKE_report.h"
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2011-03-02 06:47:08 +00:00
|
|
|
#include "RNA_access.h"
|
2012-12-23 13:58:42 +00:00
|
|
|
#include "RNA_enum_types.h"
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2011-05-08 05:41:57 +00:00
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
2017-11-29 21:11:29 +11:00
|
|
|
#include "bpy_capi_utils.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "bpy_rna.h"
|
2011-04-03 10:04:16 +00:00
|
|
|
#include "bpy_rna_anim.h"
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2015-01-06 17:39:47 +11:00
|
|
|
#include "../generic/python_utildefines.h"
|
|
|
|
|
2019-04-26 15:25:41 +02:00
|
|
|
#include "DEG_depsgraph_build.h"
|
|
|
|
|
2011-03-02 04:51:43 +00:00
|
|
|
/* for keyframes and drivers */
|
2019-01-07 15:27:59 +11:00
|
|
|
static int pyrna_struct_anim_args_parse_ex(PointerRNA *ptr,
|
2011-11-26 15:18:30 +00:00
|
|
|
const char *error_prefix,
|
|
|
|
const char *path,
|
2019-01-07 15:33:25 +11:00
|
|
|
const char **r_path_full,
|
|
|
|
int *r_index,
|
|
|
|
bool *r_path_no_validate)
|
2011-03-02 04:51:43 +00:00
|
|
|
{
|
2014-01-28 03:52:21 +11:00
|
|
|
const bool is_idbase = RNA_struct_is_ID(ptr->type);
|
2011-03-02 04:51:43 +00:00
|
|
|
PropertyRNA *prop;
|
|
|
|
PointerRNA r_ptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-12-26 12:26:11 +00:00
|
|
|
if (ptr->data == NULL) {
|
2011-04-30 13:58:31 +00:00
|
|
|
PyErr_Format(
|
|
|
|
PyExc_TypeError, "%.200s this struct has no data, can't be animated", error_prefix);
|
2011-03-02 04:51:43 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-03-02 04:51:43 +00:00
|
|
|
/* full paths can only be given from ID base */
|
2011-10-13 01:29:08 +00:00
|
|
|
if (is_idbase) {
|
2019-01-07 15:33:25 +11:00
|
|
|
int path_index = -1;
|
|
|
|
if (RNA_path_resolve_property_full(ptr, path, &r_ptr, &prop, &path_index) == false) {
|
2011-12-26 12:26:11 +00:00
|
|
|
prop = NULL;
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
2019-01-07 15:33:25 +11:00
|
|
|
else if (path_index != -1) {
|
2011-04-30 13:58:31 +00:00
|
|
|
PyErr_Format(PyExc_ValueError,
|
|
|
|
"%.200s path includes index, must be a separate argument",
|
|
|
|
error_prefix,
|
|
|
|
path);
|
2011-03-02 04:51:43 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2019-08-23 09:52:12 +02:00
|
|
|
else if (ptr->owner_id != r_ptr.owner_id) {
|
2011-04-30 13:58:31 +00:00
|
|
|
PyErr_Format(PyExc_ValueError, "%.200s path spans ID blocks", error_prefix, path);
|
2011-03-02 04:51:43 +00:00
|
|
|
return -1;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-12-26 12:26:11 +00:00
|
|
|
prop = RNA_struct_find_property(ptr, path);
|
|
|
|
r_ptr = *ptr;
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-12-26 12:26:11 +00:00
|
|
|
if (prop == NULL) {
|
2019-01-07 15:27:59 +11:00
|
|
|
if (r_path_no_validate) {
|
|
|
|
*r_path_no_validate = true;
|
|
|
|
return -1;
|
|
|
|
}
|
2011-04-30 13:58:31 +00:00
|
|
|
PyErr_Format(PyExc_TypeError, "%.200s property \"%s\" not found", error_prefix, path);
|
2011-03-02 04:51:43 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-07 15:27:59 +11:00
|
|
|
if (r_path_no_validate) {
|
|
|
|
/* Don't touch the index. */
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
|
|
|
else {
|
2019-01-07 15:27:59 +11:00
|
|
|
if (!RNA_property_animateable(&r_ptr, prop)) {
|
|
|
|
PyErr_Format(PyExc_TypeError, "%.200s property \"%s\" not animatable", error_prefix, path);
|
2011-03-02 04:51:43 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-07 15:27:59 +11:00
|
|
|
if (RNA_property_array_check(prop) == 0) {
|
2019-01-07 15:33:25 +11:00
|
|
|
if ((*r_index) == -1) {
|
|
|
|
*r_index = 0;
|
2019-01-07 15:27:59 +11:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
PyErr_Format(PyExc_TypeError,
|
|
|
|
"%.200s index %d was given while property \"%s\" is not an array",
|
2019-01-07 15:33:25 +11:00
|
|
|
error_prefix,
|
|
|
|
*r_index,
|
|
|
|
path);
|
2019-01-07 15:27:59 +11:00
|
|
|
return -1;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-01-07 15:27:59 +11:00
|
|
|
}
|
|
|
|
else {
|
2020-08-20 16:10:13 +10:00
|
|
|
const int array_len = RNA_property_array_length(&r_ptr, prop);
|
2019-01-07 15:33:25 +11:00
|
|
|
if ((*r_index) < -1 || (*r_index) >= array_len) {
|
2019-01-07 15:27:59 +11:00
|
|
|
PyErr_Format(PyExc_TypeError,
|
|
|
|
"%.200s index out of range \"%s\", given %d, array length is %d",
|
2019-01-07 15:33:25 +11:00
|
|
|
error_prefix,
|
|
|
|
path,
|
|
|
|
*r_index,
|
|
|
|
array_len);
|
2019-01-07 15:27:59 +11:00
|
|
|
return -1;
|
|
|
|
}
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (is_idbase) {
|
2019-01-07 15:33:25 +11:00
|
|
|
*r_path_full = BLI_strdup(path);
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
|
|
|
else {
|
2019-01-07 15:33:25 +11:00
|
|
|
*r_path_full = RNA_path_from_ID_to_property(&r_ptr, prop);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-07 15:33:25 +11:00
|
|
|
if (*r_path_full == NULL) {
|
2011-04-30 13:58:31 +00:00
|
|
|
PyErr_Format(PyExc_TypeError, "%.200s could not make path to \"%s\"", error_prefix, path);
|
2011-03-02 04:51:43 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-03-02 04:51:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-07 15:27:59 +11:00
|
|
|
static int pyrna_struct_anim_args_parse(PointerRNA *ptr,
|
|
|
|
const char *error_prefix,
|
|
|
|
const char *path,
|
2019-01-07 15:33:25 +11:00
|
|
|
const char **r_path_full,
|
|
|
|
int *r_index)
|
2019-01-07 15:27:59 +11:00
|
|
|
{
|
2019-01-07 15:33:25 +11:00
|
|
|
return pyrna_struct_anim_args_parse_ex(ptr, error_prefix, path, r_path_full, r_index, NULL);
|
2019-01-07 15:27:59 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-01-07 15:33:25 +11:00
|
|
|
* Unlike #pyrna_struct_anim_args_parse \a r_path_full may be copied from \a path.
|
2019-01-07 15:27:59 +11:00
|
|
|
*/
|
|
|
|
static int pyrna_struct_anim_args_parse_no_resolve(PointerRNA *ptr,
|
|
|
|
const char *error_prefix,
|
|
|
|
const char *path,
|
2019-01-07 15:33:25 +11:00
|
|
|
const char **r_path_full)
|
2019-01-07 15:27:59 +11:00
|
|
|
{
|
|
|
|
const bool is_idbase = RNA_struct_is_ID(ptr->type);
|
|
|
|
if (is_idbase) {
|
2019-01-07 15:33:25 +11:00
|
|
|
*r_path_full = path;
|
2019-01-07 15:27:59 +11:00
|
|
|
return 0;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
char *path_prefix = RNA_path_from_ID_to_struct(ptr);
|
|
|
|
if (path_prefix == NULL) {
|
|
|
|
PyErr_Format(PyExc_TypeError,
|
|
|
|
"%.200s could not make path for type %s",
|
|
|
|
error_prefix,
|
|
|
|
RNA_struct_identifier(ptr->type));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*path == '[') {
|
|
|
|
*r_path_full = BLI_string_joinN(path_prefix, path);
|
2019-01-07 15:27:59 +11:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
else {
|
|
|
|
*r_path_full = BLI_string_join_by_sep_charN('.', path_prefix, path);
|
|
|
|
}
|
|
|
|
MEM_freeN(path_prefix);
|
|
|
|
|
2019-01-07 15:27:59 +11:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int pyrna_struct_anim_args_parse_no_resolve_fallback(PointerRNA *ptr,
|
|
|
|
const char *error_prefix,
|
|
|
|
const char *path,
|
2019-01-07 15:33:25 +11:00
|
|
|
const char **r_path_full,
|
|
|
|
int *r_index)
|
2019-01-07 15:27:59 +11:00
|
|
|
{
|
|
|
|
bool path_unresolved = false;
|
|
|
|
if (pyrna_struct_anim_args_parse_ex(
|
2019-01-07 15:33:25 +11:00
|
|
|
ptr, error_prefix, path, r_path_full, r_index, &path_unresolved) == -1) {
|
2019-01-07 15:27:59 +11:00
|
|
|
if (path_unresolved == true) {
|
|
|
|
if (pyrna_struct_anim_args_parse_no_resolve(ptr, error_prefix, path, r_path_full) == -1) {
|
|
|
|
return -1;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-01-07 15:27:59 +11:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-03-02 04:51:43 +00:00
|
|
|
/* internal use for insert and delete */
|
2011-11-26 15:18:30 +00:00
|
|
|
static int pyrna_struct_keyframe_parse(PointerRNA *ptr,
|
2012-03-26 20:41:54 +00:00
|
|
|
PyObject *args,
|
|
|
|
PyObject *kw,
|
|
|
|
const char *parse_str,
|
|
|
|
const char *error_prefix,
|
2019-01-07 15:33:25 +11:00
|
|
|
/* return values */
|
|
|
|
const char **r_path_full,
|
|
|
|
int *r_index,
|
|
|
|
float *r_cfra,
|
|
|
|
const char **r_group_name,
|
|
|
|
int *r_options)
|
2011-03-02 04:51:43 +00:00
|
|
|
{
|
2012-12-23 13:58:42 +00:00
|
|
|
static const char *kwlist[] = {"data_path", "index", "frame", "group", "options", NULL};
|
|
|
|
PyObject *pyoptions = NULL;
|
2011-03-02 04:51:43 +00:00
|
|
|
const char *path;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-23 13:58:42 +00:00
|
|
|
/* note, parse_str MUST start with 's|ifsO!' */
|
2019-01-07 15:27:59 +11:00
|
|
|
if (!PyArg_ParseTupleAndKeywords(args,
|
2019-01-07 15:33:25 +11:00
|
|
|
kw,
|
|
|
|
parse_str,
|
|
|
|
(char **)kwlist,
|
|
|
|
&path,
|
|
|
|
r_index,
|
|
|
|
r_cfra,
|
|
|
|
r_group_name,
|
2019-01-07 15:27:59 +11:00
|
|
|
&PySet_Type,
|
|
|
|
&pyoptions)) {
|
2011-03-02 04:51:43 +00:00
|
|
|
return -1;
|
2012-12-23 13:58:42 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-07 15:27:59 +11:00
|
|
|
if (pyrna_struct_anim_args_parse(ptr, error_prefix, path, r_path_full, r_index) == -1) {
|
2011-03-02 04:51:43 +00:00
|
|
|
return -1;
|
2019-01-07 15:27:59 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-07 15:33:25 +11:00
|
|
|
if (*r_cfra == FLT_MAX) {
|
2020-10-15 18:20:15 +11:00
|
|
|
*r_cfra = CTX_data_scene(BPY_context_get())->r.cfra;
|
2019-01-07 15:33:25 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-23 13:58:42 +00:00
|
|
|
/* flag may be null (no option currently for remove keyframes e.g.). */
|
2019-01-07 15:33:25 +11:00
|
|
|
if (r_options) {
|
2019-05-11 21:16:46 +03:00
|
|
|
if (pyoptions &&
|
|
|
|
(pyrna_set_to_enum_bitfield(
|
|
|
|
rna_enum_keying_flag_items_api, pyoptions, r_options, error_prefix) == -1)) {
|
2014-04-29 07:34:09 +10:00
|
|
|
return -1;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-07 15:33:25 +11:00
|
|
|
*r_options |= INSERTKEY_NO_USERPREF;
|
2014-04-29 07:34:09 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-03-02 04:51:43 +00:00
|
|
|
return 0; /* success */
|
|
|
|
}
|
|
|
|
|
|
|
|
char pyrna_struct_keyframe_insert_doc[] =
|
|
|
|
".. method:: keyframe_insert(data_path, index=-1, frame=bpy.context.scene.frame_current, "
|
2019-09-25 13:41:32 +02:00
|
|
|
"group=\"\", options=set())\n"
|
2011-03-02 04:51:43 +00:00
|
|
|
"\n"
|
|
|
|
" Insert a keyframe on the property given, adding fcurves and animation data when "
|
|
|
|
"necessary.\n"
|
|
|
|
"\n"
|
|
|
|
" :arg data_path: path to the property to key, analogous to the fcurve's data path.\n"
|
|
|
|
" :type data_path: string\n"
|
2016-04-19 18:25:56 +10:00
|
|
|
" :arg index: array index of the property to key.\n"
|
|
|
|
" Defaults to -1 which will key all indices or a single channel if the property is not "
|
|
|
|
"an array.\n"
|
2011-03-02 04:51:43 +00:00
|
|
|
" :type index: int\n"
|
|
|
|
" :arg frame: The frame on which the keyframe is inserted, defaulting to the current "
|
|
|
|
"frame.\n"
|
|
|
|
" :type frame: float\n"
|
|
|
|
" :arg group: The name of the group the F-Curve should be added to if it doesn't exist "
|
|
|
|
"yet.\n"
|
|
|
|
" :type group: str\n"
|
2019-09-25 13:41:32 +02:00
|
|
|
" :arg options: Optional set of flags:\n"
|
2016-04-19 18:25:56 +10:00
|
|
|
"\n"
|
|
|
|
" - ``INSERTKEY_NEEDED`` Only insert keyframes where they're needed in the relevant "
|
|
|
|
"F-Curves.\n"
|
|
|
|
" - ``INSERTKEY_VISUAL`` Insert keyframes based on 'visual transforms'.\n"
|
|
|
|
" - ``INSERTKEY_XYZ_TO_RGB`` Color for newly added transformation F-Curves (Location, "
|
2019-05-11 21:16:46 +03:00
|
|
|
"Rotation, Scale) is based on the transform axis.\n"
|
2019-08-01 13:53:25 +10:00
|
|
|
" - ``INSERTKEY_REPLACE`` Only replace already existing keyframes.\n"
|
2019-05-11 21:16:46 +03:00
|
|
|
" - ``INSERTKEY_AVAILABLE`` Only insert into already existing F-Curves.\n"
|
|
|
|
" - ``INSERTKEY_CYCLE_AWARE`` Take cyclic extrapolation into account "
|
|
|
|
"(Cycle-Aware Keying option).\n"
|
2012-12-23 13:58:42 +00:00
|
|
|
" :type flag: set\n"
|
2011-03-02 04:51:43 +00:00
|
|
|
" :return: Success of keyframe insertion.\n"
|
|
|
|
" :rtype: boolean\n";
|
|
|
|
PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyObject *kw)
|
|
|
|
{
|
|
|
|
/* args, pyrna_struct_keyframe_parse handles these */
|
2011-12-26 12:26:11 +00:00
|
|
|
const char *path_full = NULL;
|
|
|
|
int index = -1;
|
|
|
|
float cfra = FLT_MAX;
|
|
|
|
const char *group_name = NULL;
|
2020-08-20 16:10:13 +10:00
|
|
|
const char keytype = BEZT_KEYTYPE_KEYFRAME; /* XXX: Expose this as a one-off option... */
|
2012-12-23 13:58:42 +00:00
|
|
|
int options = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-10-10 07:10:53 +00:00
|
|
|
PYRNA_STRUCT_CHECK_OBJ(self);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-07 15:33:25 +11:00
|
|
|
if (pyrna_struct_keyframe_parse(&self->ptr,
|
|
|
|
args,
|
|
|
|
kw,
|
PyAPI: use keyword only arguments
Use keyword only arguments for the following functions.
- addon_utils.module_bl_info 2nd arg `info_basis`.
- addon_utils.modules 1st `module_cache`, 2nd arg `refresh`.
- addon_utils.modules_refresh 1st arg `module_cache`.
- bl_app_template_utils.activate 1nd arg `template_id`.
- bl_app_template_utils.import_from_id 2nd arg `ignore_not_found`.
- bl_app_template_utils.import_from_path 2nd arg `ignore_not_found`.
- bl_keymap_utils.keymap_from_toolbar.generate 2nd & 3rd args `use_fallback_keys` & `use_reset`.
- bl_keymap_utils.platform_helpers.keyconfig_data_oskey_from_ctrl 2nd arg `filter_fn`.
- bl_ui_utils.bug_report_url.url_prefill_from_blender 1st arg `addon_info`.
- bmesh.types.BMFace.copy 1st & 2nd args `verts`, `edges`.
- bmesh.types.BMesh.calc_volume 1st arg `signed`.
- bmesh.types.BMesh.from_mesh 2nd..4th args `face_normals`, `use_shape_key`, `shape_key_index`.
- bmesh.types.BMesh.from_object 3rd & 4th args `cage`, `face_normals`.
- bmesh.types.BMesh.transform 2nd arg `filter`.
- bmesh.types.BMesh.update_edit_mesh 2nd & 3rd args `loop_triangles`, `destructive`.
- bmesh.types.{BMVertSeq,BMEdgeSeq,BMFaceSeq}.sort 1st & 2nd arg `key`, `reverse`.
- bmesh.utils.face_split 4th..6th args `coords`, `use_exist`, `example`.
- bpy.data.libraries.load 2nd..4th args `link`, `relative`, `assets_only`.
- bpy.data.user_map 1st..3rd args `subset`, `key_types, `value_types`.
- bpy.msgbus.subscribe_rna 5th arg `options`.
- bpy.path.abspath 2nd & 3rd args `start` & `library`.
- bpy.path.clean_name 2nd arg `replace`.
- bpy.path.ensure_ext 3rd arg `case_sensitive`.
- bpy.path.module_names 2nd arg `recursive`.
- bpy.path.relpath 2nd arg `start`.
- bpy.types.EditBone.transform 2nd & 3rd arg `scale`, `roll`.
- bpy.types.Operator.as_keywords 1st arg `ignore`.
- bpy.types.Struct.{keyframe_insert,keyframe_delete} 2nd..5th args `index`, `frame`, `group`, `options`.
- bpy.types.WindowManager.popup_menu 2nd & 3rd arg `title`, `icon`.
- bpy.types.WindowManager.popup_menu_pie 3rd & 4th arg `title`, `icon`.
- bpy.utils.app_template_paths 1st arg `subdir`.
- bpy.utils.app_template_paths 1st arg `subdir`.
- bpy.utils.blend_paths 1st..3rd args `absolute`, `packed`, `local`.
- bpy.utils.execfile 2nd arg `mod`.
- bpy.utils.keyconfig_set 2nd arg `report`.
- bpy.utils.load_scripts 1st & 2nd `reload_scripts` & `refresh_scripts`.
- bpy.utils.preset_find 3rd & 4th args `display_name`, `ext`.
- bpy.utils.resource_path 2nd & 3rd arg `major`, `minor`.
- bpy.utils.script_paths 1st..4th args `subdir`, `user_pref`, `check_all`, `use_user`.
- bpy.utils.smpte_from_frame 2nd & 3rd args `fps`, `fps_base`.
- bpy.utils.smpte_from_seconds 2nd & 3rd args `fps`, `fps_base`.
- bpy.utils.system_resource 2nd arg `subdir`.
- bpy.utils.time_from_frame 2nd & 3rd args `fps`, `fps_base`.
- bpy.utils.time_to_frame 2nd & 3rd args `fps`, `fps_base`.
- bpy.utils.units.to_string 4th..6th `precision`, `split_unit`, `compatible_unit`.
- bpy.utils.units.to_value 4th arg `str_ref_unit`.
- bpy.utils.user_resource 2nd & 3rd args `subdir`, `create`
- bpy_extras.view3d_utils.location_3d_to_region_2d 4th arg `default`.
- bpy_extras.view3d_utils.region_2d_to_origin_3d 4th arg `clamp`.
- gpu.offscreen.unbind 1st arg `restore`.
- gpu_extras.batch.batch_for_shader 4th arg `indices`.
- gpu_extras.batch.presets.draw_circle_2d 4th arg `segments`.
- gpu_extras.presets.draw_circle_2d 4th arg `segments`.
- imbuf.types.ImBuf.resize 2nd arg `resize`.
- imbuf.write 2nd arg `filepath`.
- mathutils.kdtree.KDTree.find 2nd arg `filter`.
- nodeitems_utils.NodeCategory 3rd & 4th arg `descriptions`, `items`.
- nodeitems_utils.NodeItem 2nd..4th args `label`, `settings`, `poll`.
- nodeitems_utils.NodeItemCustom 1st & 2nd arg `poll`, `draw`.
- rna_prop_ui.draw 5th arg `use_edit`.
- rna_prop_ui.rna_idprop_ui_get 2nd arg `create`.
- rna_prop_ui.rna_idprop_ui_prop_clear 3rd arg `remove`.
- rna_prop_ui.rna_idprop_ui_prop_get 3rd arg `create`.
- rna_xml.xml2rna 2nd arg `root_rna`.
- rna_xml.xml_file_write 4th arg `skip_typemap`.
2021-06-08 18:03:14 +10:00
|
|
|
"s|$ifsO!:bpy_struct.keyframe_insert()",
|
2019-01-07 15:33:25 +11:00
|
|
|
"bpy_struct.keyframe_insert()",
|
|
|
|
&path_full,
|
|
|
|
&index,
|
|
|
|
&cfra,
|
|
|
|
&group_name,
|
|
|
|
&options) == -1) {
|
2011-03-02 04:51:43 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
T77086 Animation: Passing Dependency Graph to Drivers
Custom driver functions need access to the dependency graph that is
triggering the evaluation of the driver. This patch passes the
dependency graph pointer through all the animation-related calls.
Instead of passing the evaluation time to functions, the code now passes
an `AnimationEvalContext` pointer:
```
typedef struct AnimationEvalContext {
struct Depsgraph *const depsgraph;
const float eval_time;
} AnimationEvalContext;
```
These structs are read-only, meaning that the code cannot change the
evaluation time. Note that the `depsgraph` pointer itself is const, but
it points to a non-const depsgraph.
FCurves and Drivers can be evaluated at a different time than the
current scene time, for example when evaluating NLA strips. This means
that, even though the current time is stored in the dependency graph, we
need an explicit evaluation time.
There are two functions that allow creation of `AnimationEvalContext`
objects:
- `BKE_animsys_eval_context_construct(Depsgraph *depsgraph, float
eval_time)`, which creates a new context object from scratch, and
- `BKE_animsys_eval_context_construct_at(AnimationEvalContext
*anim_eval_context, float eval_time)`, which can be used to create a
`AnimationEvalContext` with the same depsgraph, but at a different
time. This makes it possible to later add fields without changing any
of the code that just want to change the eval time.
This also provides a fix for T75553, although it does require a change
to the custom driver function. The driver should call
`custom_function(depsgraph)`, and the function should use that depsgraph
instead of information from `bpy.context`.
Reviewed By: brecht, sergey
Differential Revision: https://developer.blender.org/D8047
2020-07-17 17:38:09 +02:00
|
|
|
|
|
|
|
/* This assumes that keyframes are only added on original data & using the active depsgraph. If
|
|
|
|
* it turns out to be necessary for some reason to insert keyframes on evaluated objects, we can
|
|
|
|
* revisit this and add an explicit `depsgraph` keyword argument to the function call.
|
|
|
|
*
|
|
|
|
* It is unlikely that driver code (which is the reason this depsgraph pointer is obtained) will
|
|
|
|
* be executed from this function call, as this only happens when `options` has
|
|
|
|
* `INSERTKEY_DRIVER`, which is not exposed to Python. */
|
2020-10-15 18:20:15 +11:00
|
|
|
bContext *C = BPY_context_get();
|
T77086 Animation: Passing Dependency Graph to Drivers
Custom driver functions need access to the dependency graph that is
triggering the evaluation of the driver. This patch passes the
dependency graph pointer through all the animation-related calls.
Instead of passing the evaluation time to functions, the code now passes
an `AnimationEvalContext` pointer:
```
typedef struct AnimationEvalContext {
struct Depsgraph *const depsgraph;
const float eval_time;
} AnimationEvalContext;
```
These structs are read-only, meaning that the code cannot change the
evaluation time. Note that the `depsgraph` pointer itself is const, but
it points to a non-const depsgraph.
FCurves and Drivers can be evaluated at a different time than the
current scene time, for example when evaluating NLA strips. This means
that, even though the current time is stored in the dependency graph, we
need an explicit evaluation time.
There are two functions that allow creation of `AnimationEvalContext`
objects:
- `BKE_animsys_eval_context_construct(Depsgraph *depsgraph, float
eval_time)`, which creates a new context object from scratch, and
- `BKE_animsys_eval_context_construct_at(AnimationEvalContext
*anim_eval_context, float eval_time)`, which can be used to create a
`AnimationEvalContext` with the same depsgraph, but at a different
time. This makes it possible to later add fields without changing any
of the code that just want to change the eval time.
This also provides a fix for T75553, although it does require a change
to the custom driver function. The driver should call
`custom_function(depsgraph)`, and the function should use that depsgraph
instead of information from `bpy.context`.
Reviewed By: brecht, sergey
Differential Revision: https://developer.blender.org/D8047
2020-07-17 17:38:09 +02:00
|
|
|
struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
|
|
|
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
|
|
|
|
cfra);
|
|
|
|
|
|
|
|
if (self->ptr.type == &RNA_NlaStrip) {
|
2016-12-28 23:20:25 +13:00
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
ReportList reports;
|
2020-03-06 16:45:56 +11:00
|
|
|
bool result = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-12-28 23:20:25 +13:00
|
|
|
PointerRNA ptr = self->ptr;
|
|
|
|
PropertyRNA *prop = NULL;
|
|
|
|
const char *prop_name;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-12-28 23:20:25 +13:00
|
|
|
BKE_reports_init(&reports, RPT_STORE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-12-28 23:20:25 +13:00
|
|
|
/* Retrieve the property identifier from the full path, since we can't get it any other way */
|
|
|
|
prop_name = strrchr(path_full, '.');
|
|
|
|
if ((prop_name >= path_full) && (prop_name + 1 < path_full + strlen(path_full))) {
|
|
|
|
prop = RNA_struct_find_property(&ptr, prop_name + 1);
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-12-28 23:20:25 +13:00
|
|
|
if (prop) {
|
2020-03-05 08:33:26 +11:00
|
|
|
NlaStrip *strip = ptr.data;
|
2020-06-05 09:30:15 +02:00
|
|
|
FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
|
T77086 Animation: Passing Dependency Graph to Drivers
Custom driver functions need access to the dependency graph that is
triggering the evaluation of the driver. This patch passes the
dependency graph pointer through all the animation-related calls.
Instead of passing the evaluation time to functions, the code now passes
an `AnimationEvalContext` pointer:
```
typedef struct AnimationEvalContext {
struct Depsgraph *const depsgraph;
const float eval_time;
} AnimationEvalContext;
```
These structs are read-only, meaning that the code cannot change the
evaluation time. Note that the `depsgraph` pointer itself is const, but
it points to a non-const depsgraph.
FCurves and Drivers can be evaluated at a different time than the
current scene time, for example when evaluating NLA strips. This means
that, even though the current time is stored in the dependency graph, we
need an explicit evaluation time.
There are two functions that allow creation of `AnimationEvalContext`
objects:
- `BKE_animsys_eval_context_construct(Depsgraph *depsgraph, float
eval_time)`, which creates a new context object from scratch, and
- `BKE_animsys_eval_context_construct_at(AnimationEvalContext
*anim_eval_context, float eval_time)`, which can be used to create a
`AnimationEvalContext` with the same depsgraph, but at a different
time. This makes it possible to later add fields without changing any
of the code that just want to change the eval time.
This also provides a fix for T75553, although it does require a change
to the custom driver function. The driver should call
`custom_function(depsgraph)`, and the function should use that depsgraph
instead of information from `bpy.context`.
Reviewed By: brecht, sergey
Differential Revision: https://developer.blender.org/D8047
2020-07-17 17:38:09 +02:00
|
|
|
result = insert_keyframe_direct(
|
|
|
|
&reports, ptr, prop, fcu, &anim_eval_context, keytype, NULL, options);
|
2016-12-28 23:20:25 +13:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full);
|
|
|
|
}
|
|
|
|
MEM_freeN((void *)path_full);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-30 06:12:48 +11:00
|
|
|
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
|
2016-12-28 23:20:25 +13:00
|
|
|
return NULL;
|
2019-03-30 06:12:48 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-12-28 23:20:25 +13:00
|
|
|
return PyBool_FromLong(result);
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
ID *id = self->ptr.owner_id;
|
|
|
|
ReportList reports;
|
|
|
|
bool result;
|
|
|
|
|
|
|
|
BKE_reports_init(&reports, RPT_STORE);
|
|
|
|
|
|
|
|
BLI_assert(BKE_id_is_in_global_main(id));
|
|
|
|
result = (insert_keyframe(G_MAIN,
|
|
|
|
&reports,
|
|
|
|
id,
|
|
|
|
NULL,
|
|
|
|
group_name,
|
|
|
|
path_full,
|
|
|
|
index,
|
|
|
|
&anim_eval_context,
|
|
|
|
keytype,
|
|
|
|
NULL,
|
|
|
|
options) != 0);
|
|
|
|
MEM_freeN((void *)path_full);
|
|
|
|
|
|
|
|
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
|
|
|
|
return NULL;
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
|
|
|
|
return PyBool_FromLong(result);
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
char pyrna_struct_keyframe_delete_doc[] =
|
|
|
|
".. method:: keyframe_delete(data_path, index=-1, frame=bpy.context.scene.frame_current, "
|
|
|
|
"group=\"\")\n"
|
|
|
|
"\n"
|
|
|
|
" Remove a keyframe from this properties fcurve.\n"
|
|
|
|
"\n"
|
|
|
|
" :arg data_path: path to the property to remove a key, analogous to the fcurve's data "
|
|
|
|
"path.\n"
|
|
|
|
" :type data_path: string\n"
|
|
|
|
" :arg index: array index of the property to remove a key. Defaults to -1 removing all "
|
|
|
|
"indices or a single channel if the property is not an array.\n"
|
|
|
|
" :type index: int\n"
|
|
|
|
" :arg frame: The frame on which the keyframe is deleted, defaulting to the current frame.\n"
|
|
|
|
" :type frame: float\n"
|
|
|
|
" :arg group: The name of the group the F-Curve should be added to if it doesn't exist "
|
|
|
|
"yet.\n"
|
|
|
|
" :type group: str\n"
|
2020-07-10 16:04:09 +10:00
|
|
|
" :return: Success of keyframe deletion.\n"
|
2011-03-02 04:51:43 +00:00
|
|
|
" :rtype: boolean\n";
|
|
|
|
PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyObject *kw)
|
|
|
|
{
|
|
|
|
/* args, pyrna_struct_keyframe_parse handles these */
|
2011-12-26 12:26:11 +00:00
|
|
|
const char *path_full = NULL;
|
|
|
|
int index = -1;
|
|
|
|
float cfra = FLT_MAX;
|
|
|
|
const char *group_name = NULL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-10-10 07:10:53 +00:00
|
|
|
PYRNA_STRUCT_CHECK_OBJ(self);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (pyrna_struct_keyframe_parse(&self->ptr,
|
|
|
|
args,
|
|
|
|
kw,
|
PyAPI: use keyword only arguments
Use keyword only arguments for the following functions.
- addon_utils.module_bl_info 2nd arg `info_basis`.
- addon_utils.modules 1st `module_cache`, 2nd arg `refresh`.
- addon_utils.modules_refresh 1st arg `module_cache`.
- bl_app_template_utils.activate 1nd arg `template_id`.
- bl_app_template_utils.import_from_id 2nd arg `ignore_not_found`.
- bl_app_template_utils.import_from_path 2nd arg `ignore_not_found`.
- bl_keymap_utils.keymap_from_toolbar.generate 2nd & 3rd args `use_fallback_keys` & `use_reset`.
- bl_keymap_utils.platform_helpers.keyconfig_data_oskey_from_ctrl 2nd arg `filter_fn`.
- bl_ui_utils.bug_report_url.url_prefill_from_blender 1st arg `addon_info`.
- bmesh.types.BMFace.copy 1st & 2nd args `verts`, `edges`.
- bmesh.types.BMesh.calc_volume 1st arg `signed`.
- bmesh.types.BMesh.from_mesh 2nd..4th args `face_normals`, `use_shape_key`, `shape_key_index`.
- bmesh.types.BMesh.from_object 3rd & 4th args `cage`, `face_normals`.
- bmesh.types.BMesh.transform 2nd arg `filter`.
- bmesh.types.BMesh.update_edit_mesh 2nd & 3rd args `loop_triangles`, `destructive`.
- bmesh.types.{BMVertSeq,BMEdgeSeq,BMFaceSeq}.sort 1st & 2nd arg `key`, `reverse`.
- bmesh.utils.face_split 4th..6th args `coords`, `use_exist`, `example`.
- bpy.data.libraries.load 2nd..4th args `link`, `relative`, `assets_only`.
- bpy.data.user_map 1st..3rd args `subset`, `key_types, `value_types`.
- bpy.msgbus.subscribe_rna 5th arg `options`.
- bpy.path.abspath 2nd & 3rd args `start` & `library`.
- bpy.path.clean_name 2nd arg `replace`.
- bpy.path.ensure_ext 3rd arg `case_sensitive`.
- bpy.path.module_names 2nd arg `recursive`.
- bpy.path.relpath 2nd arg `start`.
- bpy.types.EditBone.transform 2nd & 3rd arg `scale`, `roll`.
- bpy.types.Operator.as_keywords 1st arg `ignore`.
- bpy.types.Struct.{keyframe_insert,keyframe_delete} 2nd..5th args `index`, `frame`, `group`, `options`.
- bpy.types.WindowManager.popup_menu 2nd & 3rd arg `title`, `icon`.
- bpy.types.WindowManager.popup_menu_pie 3rd & 4th arg `title`, `icon`.
- bpy.utils.app_template_paths 1st arg `subdir`.
- bpy.utils.app_template_paths 1st arg `subdir`.
- bpy.utils.blend_paths 1st..3rd args `absolute`, `packed`, `local`.
- bpy.utils.execfile 2nd arg `mod`.
- bpy.utils.keyconfig_set 2nd arg `report`.
- bpy.utils.load_scripts 1st & 2nd `reload_scripts` & `refresh_scripts`.
- bpy.utils.preset_find 3rd & 4th args `display_name`, `ext`.
- bpy.utils.resource_path 2nd & 3rd arg `major`, `minor`.
- bpy.utils.script_paths 1st..4th args `subdir`, `user_pref`, `check_all`, `use_user`.
- bpy.utils.smpte_from_frame 2nd & 3rd args `fps`, `fps_base`.
- bpy.utils.smpte_from_seconds 2nd & 3rd args `fps`, `fps_base`.
- bpy.utils.system_resource 2nd arg `subdir`.
- bpy.utils.time_from_frame 2nd & 3rd args `fps`, `fps_base`.
- bpy.utils.time_to_frame 2nd & 3rd args `fps`, `fps_base`.
- bpy.utils.units.to_string 4th..6th `precision`, `split_unit`, `compatible_unit`.
- bpy.utils.units.to_value 4th arg `str_ref_unit`.
- bpy.utils.user_resource 2nd & 3rd args `subdir`, `create`
- bpy_extras.view3d_utils.location_3d_to_region_2d 4th arg `default`.
- bpy_extras.view3d_utils.region_2d_to_origin_3d 4th arg `clamp`.
- gpu.offscreen.unbind 1st arg `restore`.
- gpu_extras.batch.batch_for_shader 4th arg `indices`.
- gpu_extras.batch.presets.draw_circle_2d 4th arg `segments`.
- gpu_extras.presets.draw_circle_2d 4th arg `segments`.
- imbuf.types.ImBuf.resize 2nd arg `resize`.
- imbuf.write 2nd arg `filepath`.
- mathutils.kdtree.KDTree.find 2nd arg `filter`.
- nodeitems_utils.NodeCategory 3rd & 4th arg `descriptions`, `items`.
- nodeitems_utils.NodeItem 2nd..4th args `label`, `settings`, `poll`.
- nodeitems_utils.NodeItemCustom 1st & 2nd arg `poll`, `draw`.
- rna_prop_ui.draw 5th arg `use_edit`.
- rna_prop_ui.rna_idprop_ui_get 2nd arg `create`.
- rna_prop_ui.rna_idprop_ui_prop_clear 3rd arg `remove`.
- rna_prop_ui.rna_idprop_ui_prop_get 3rd arg `create`.
- rna_xml.xml2rna 2nd arg `root_rna`.
- rna_xml.xml_file_write 4th arg `skip_typemap`.
2021-06-08 18:03:14 +10:00
|
|
|
"s|$ifsO!:bpy_struct.keyframe_delete()",
|
2012-03-26 20:41:54 +00:00
|
|
|
"bpy_struct.keyframe_insert()",
|
2012-12-23 13:58:42 +00:00
|
|
|
&path_full,
|
|
|
|
&index,
|
|
|
|
&cfra,
|
|
|
|
&group_name,
|
|
|
|
NULL) == -1) {
|
2011-03-02 04:51:43 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
if (self->ptr.type == &RNA_NlaStrip) {
|
2016-12-28 23:27:46 +13:00
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
ReportList reports;
|
2020-03-06 16:45:56 +11:00
|
|
|
bool result = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-12-28 23:27:46 +13:00
|
|
|
PointerRNA ptr = self->ptr;
|
|
|
|
PropertyRNA *prop = NULL;
|
|
|
|
const char *prop_name;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-12-28 23:27:46 +13:00
|
|
|
BKE_reports_init(&reports, RPT_STORE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-12-28 23:27:46 +13:00
|
|
|
/* Retrieve the property identifier from the full path, since we can't get it any other way */
|
|
|
|
prop_name = strrchr(path_full, '.');
|
|
|
|
if ((prop_name >= path_full) && (prop_name + 1 < path_full + strlen(path_full))) {
|
|
|
|
prop = RNA_struct_find_property(&ptr, prop_name + 1);
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-12-28 23:27:46 +13:00
|
|
|
if (prop) {
|
2019-08-23 09:52:12 +02:00
|
|
|
ID *id = ptr.owner_id;
|
2020-03-05 08:33:26 +11:00
|
|
|
NlaStrip *strip = ptr.data;
|
2020-06-05 09:30:15 +02:00
|
|
|
FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-08-14 23:29:46 +10:00
|
|
|
/* NOTE: This should be true, or else we wouldn't be able to get here. */
|
|
|
|
BLI_assert(fcu != NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-12-28 23:27:46 +13:00
|
|
|
if (BKE_fcurve_is_protected(fcu)) {
|
|
|
|
BKE_reportf(
|
|
|
|
&reports,
|
|
|
|
RPT_WARNING,
|
|
|
|
"Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'",
|
|
|
|
strip->name,
|
2020-03-19 19:37:00 +01:00
|
|
|
BKE_idtype_idcode_to_name(GS(id->name)),
|
2016-12-28 23:27:46 +13:00
|
|
|
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;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-12-28 23:27:46 +13:00
|
|
|
/* try to find index of beztriple to get rid of */
|
2020-10-13 16:36:31 +11:00
|
|
|
i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, cfra, fcu->totvert, &found);
|
2016-12-28 23:27:46 +13:00
|
|
|
if (found) {
|
|
|
|
/* delete the key at the index (will sanity check + do recalc afterwards) */
|
|
|
|
delete_fcurve_key(fcu, i, 1);
|
|
|
|
result = true;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
2016-12-28 23:27:46 +13:00
|
|
|
else {
|
|
|
|
BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full);
|
|
|
|
}
|
|
|
|
MEM_freeN((void *)path_full);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-30 06:12:48 +11:00
|
|
|
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
|
2016-12-28 23:27:46 +13:00
|
|
|
return NULL;
|
2019-03-30 06:12:48 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-12-28 23:27:46 +13:00
|
|
|
return PyBool_FromLong(result);
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
bool result;
|
|
|
|
ReportList reports;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
BKE_reports_init(&reports, RPT_STORE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
result = (delete_keyframe(G.main, &reports, self->ptr.owner_id, NULL, path_full, index, cfra) !=
|
|
|
|
0);
|
|
|
|
MEM_freeN((void *)path_full);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
|
|
|
|
return NULL;
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
|
|
|
|
return PyBool_FromLong(result);
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
char pyrna_struct_driver_add_doc[] =
|
|
|
|
".. method:: driver_add(path, index=-1)\n"
|
|
|
|
"\n"
|
|
|
|
" Adds driver(s) to the given property\n"
|
|
|
|
"\n"
|
|
|
|
" :arg path: path to the property to drive, analogous to the fcurve's data path.\n"
|
|
|
|
" :type path: string\n"
|
|
|
|
" :arg index: array index of the property drive. Defaults to -1 for all indices or a single "
|
|
|
|
"channel if the property is not an array.\n"
|
|
|
|
" :type index: int\n"
|
|
|
|
" :return: The driver(s) added.\n"
|
2011-10-09 02:24:51 +00:00
|
|
|
" :rtype: :class:`bpy.types.FCurve` or list if index is -1 with an array property.\n";
|
2011-03-02 04:51:43 +00:00
|
|
|
PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args)
|
|
|
|
{
|
|
|
|
const char *path, *path_full;
|
2011-12-26 12:26:11 +00:00
|
|
|
int index = -1;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-10-10 07:10:53 +00:00
|
|
|
PYRNA_STRUCT_CHECK_OBJ(self);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-30 06:12:48 +11:00
|
|
|
if (!PyArg_ParseTuple(args, "s|i:driver_add", &path, &index)) {
|
2011-03-02 04:51:43 +00:00
|
|
|
return NULL;
|
2019-03-30 06:12:48 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-07 15:27:59 +11:00
|
|
|
if (pyrna_struct_anim_args_parse(
|
|
|
|
&self->ptr, "bpy_struct.driver_add():", path, &path_full, &index) == -1) {
|
2011-03-02 04:51:43 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
PyObject *ret = NULL;
|
|
|
|
ReportList reports;
|
|
|
|
int result;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
BKE_reports_init(&reports, RPT_STORE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
result = ANIM_add_driver(&reports,
|
|
|
|
(ID *)self->ptr.owner_id,
|
|
|
|
path_full,
|
|
|
|
index,
|
|
|
|
CREATEDRIVER_WITH_FMODIFIER,
|
|
|
|
DRIVER_TYPE_PYTHON);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
if (result) {
|
|
|
|
ID *id = self->ptr.owner_id;
|
|
|
|
AnimData *adt = BKE_animdata_from_id(id);
|
|
|
|
FCurve *fcu;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
PointerRNA tptr;
|
|
|
|
|
|
|
|
if (index == -1) { /* all, use a list */
|
|
|
|
int i = 0;
|
|
|
|
ret = PyList_New(0);
|
|
|
|
while ((fcu = BKE_fcurve_find(&adt->drivers, path_full, i++))) {
|
2011-03-02 04:51:43 +00:00
|
|
|
RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
|
2020-08-07 12:41:06 +02:00
|
|
|
PyList_APPEND(ret, pyrna_struct_CreatePyObject(&tptr));
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-08-07 12:41:06 +02:00
|
|
|
fcu = BKE_fcurve_find(&adt->drivers, path_full, index);
|
|
|
|
RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
|
|
|
|
ret = pyrna_struct_CreatePyObject(&tptr);
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-15 18:20:15 +11:00
|
|
|
bContext *context = BPY_context_get();
|
|
|
|
WM_event_add_notifier(BPY_context_get(), NC_ANIMATION | ND_FCURVES_ORDER, NULL);
|
2020-08-07 12:41:06 +02:00
|
|
|
DEG_relations_tag_update(CTX_data_main(context));
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
else {
|
|
|
|
/* XXX, should be handled by reports, */
|
|
|
|
PyErr_SetString(PyExc_TypeError,
|
|
|
|
"bpy_struct.driver_add(): failed because of an internal error");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN((void *)path_full);
|
|
|
|
|
|
|
|
return ret;
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
char pyrna_struct_driver_remove_doc[] =
|
|
|
|
".. method:: driver_remove(path, index=-1)\n"
|
|
|
|
"\n"
|
|
|
|
" Remove driver(s) from the given property\n"
|
|
|
|
"\n"
|
|
|
|
" :arg path: path to the property to drive, analogous to the fcurve's data path.\n"
|
|
|
|
" :type path: string\n"
|
|
|
|
" :arg index: array index of the property drive. Defaults to -1 for all indices or a single "
|
|
|
|
"channel if the property is not an array.\n"
|
|
|
|
" :type index: int\n"
|
|
|
|
" :return: Success of driver removal.\n"
|
|
|
|
" :rtype: boolean\n";
|
|
|
|
PyObject *pyrna_struct_driver_remove(BPy_StructRNA *self, PyObject *args)
|
|
|
|
{
|
|
|
|
const char *path, *path_full;
|
2011-12-26 12:26:11 +00:00
|
|
|
int index = -1;
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2011-10-10 07:10:53 +00:00
|
|
|
PYRNA_STRUCT_CHECK_OBJ(self);
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2019-01-07 15:27:59 +11:00
|
|
|
if (!PyArg_ParseTuple(args, "s|i:driver_remove", &path, &index)) {
|
2011-03-02 04:51:43 +00:00
|
|
|
return NULL;
|
2019-01-07 15:27:59 +11:00
|
|
|
}
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2019-01-07 15:27:59 +11:00
|
|
|
if (pyrna_struct_anim_args_parse_no_resolve_fallback(
|
|
|
|
&self->ptr, "bpy_struct.driver_remove():", path, &path_full, &index) == -1) {
|
2011-03-02 04:51:43 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
short result;
|
|
|
|
ReportList reports;
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
BKE_reports_init(&reports, RPT_STORE);
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
result = ANIM_remove_driver(&reports, (ID *)self->ptr.owner_id, path_full, index, 0);
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
if (path != path_full) {
|
|
|
|
MEM_freeN((void *)path_full);
|
|
|
|
}
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
|
|
|
|
return NULL;
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
|
2020-10-15 18:20:15 +11:00
|
|
|
bContext *context = BPY_context_get();
|
2020-08-07 12:41:06 +02:00
|
|
|
WM_event_add_notifier(context, NC_ANIMATION | ND_FCURVES_ORDER, NULL);
|
|
|
|
DEG_relations_tag_update(CTX_data_main(context));
|
|
|
|
|
|
|
|
return PyBool_FromLong(result);
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|