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"
|
|
|
|
|
2012-02-26 23:59:08 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2011-03-02 04:51:43 +00:00
|
|
|
#include "BLI_string.h"
|
2019-01-07 15:27:59 +11:00
|
|
|
#include "BLI_string_utils.h"
|
2011-03-02 04:51:43 +00:00
|
|
|
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "DNA_anim_types.h"
|
2016-12-28 23:27:46 +13:00
|
|
|
|
2011-03-02 04:51:43 +00:00
|
|
|
#include "ED_keyframing.h"
|
2016-12-28 23:27:46 +13:00
|
|
|
#include "ED_keyframes_edit.h"
|
2011-03-02 04:51:43 +00: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"
|
2016-12-28 23:27:46 +13:00
|
|
|
#include "BKE_idcode.h"
|
2018-06-22 11:37:47 +02:00
|
|
|
#include "BKE_library.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"
|
|
|
|
|
2011-03-02 04:51:43 +00:00
|
|
|
#include "bpy_rna.h"
|
2017-11-29 21:11:29 +11:00
|
|
|
#include "bpy_capi_utils.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"
|
|
|
|
|
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(
|
2011-11-26 15:18:30 +00:00
|
|
|
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, 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;
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
2011-10-13 01:29:08 +00:00
|
|
|
else if (ptr->id.data != r_ptr.id.data) {
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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-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)) {
|
2011-04-30 13:58:31 +00:00
|
|
|
PyErr_Format(PyExc_TypeError,
|
2019-01-07 15:27:59 +11:00
|
|
|
"%.200s property \"%s\" not animatable",
|
|
|
|
error_prefix, path);
|
2011-03-02 04:51:43 +00:00
|
|
|
return -1;
|
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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);
|
2011-03-02 04:51:43 +00: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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
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 == '[') {
|
2019-01-07 15:33:25 +11:00
|
|
|
*r_path_full = BLI_string_joinN(path_prefix, path);
|
2019-01-07 15:27:59 +11:00
|
|
|
}
|
|
|
|
else {
|
2019-01-07 15:33:25 +11:00
|
|
|
*r_path_full = BLI_string_join_by_sep_charN('.', path_prefix, path);
|
2019-01-07 15:27:59 +11:00
|
|
|
}
|
|
|
|
MEM_freeN(path_prefix);
|
|
|
|
}
|
|
|
|
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(
|
|
|
|
ptr, error_prefix, path,
|
2019-01-07 15:33:25 +11:00
|
|
|
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(
|
2019-01-07 15:33:25 +11:00
|
|
|
ptr, error_prefix, path, r_path_full) == -1)
|
2019-01-07 15:27:59 +11:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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(
|
2012-03-26 20:41:54 +00:00
|
|
|
PointerRNA *ptr, 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;
|
|
|
|
|
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(
|
2019-01-07 15:33:25 +11:00
|
|
|
args, kw, parse_str, (char **)kwlist, &path, r_index, r_cfra, r_group_name,
|
2019-01-07 15:27:59 +11:00
|
|
|
&PySet_Type, &pyoptions))
|
2013-03-01 14:47:06 +00:00
|
|
|
{
|
2011-03-02 04:51:43 +00:00
|
|
|
return -1;
|
2012-12-23 13:58:42 +00:00
|
|
|
}
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2019-01-07 15:27:59 +11:00
|
|
|
if (pyrna_struct_anim_args_parse(
|
|
|
|
ptr, error_prefix, path,
|
2019-01-07 15:33:25 +11:00
|
|
|
r_path_full, r_index) == -1)
|
2019-01-07 15:27:59 +11:00
|
|
|
{
|
2011-03-02 04:51:43 +00:00
|
|
|
return -1;
|
2019-01-07 15:27:59 +11:00
|
|
|
}
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2019-01-07 15:33:25 +11:00
|
|
|
if (*r_cfra == FLT_MAX) {
|
|
|
|
*r_cfra = CTX_data_scene(BPy_GetContext())->r.cfra;
|
|
|
|
}
|
2011-03-02 04:51:43 +00: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) {
|
|
|
|
if (pyoptions &&
|
|
|
|
(pyrna_set_to_enum_bitfield(
|
|
|
|
rna_enum_keying_flag_items, pyoptions, r_options, error_prefix) == -1))
|
|
|
|
{
|
2014-04-29 07:34:09 +10:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-01-07 15:33:25 +11:00
|
|
|
*r_options |= INSERTKEY_NO_USERPREF;
|
2014-04-29 07:34:09 +10:00
|
|
|
}
|
2012-12-23 13:58:42 +00: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, group=\"\")\n"
|
|
|
|
"\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"
|
2016-04-19 18:25:56 +10:00
|
|
|
" :arg options: Optional flags:\n"
|
|
|
|
"\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, Rotation, Scale)\n"
|
|
|
|
" and also Color is based on the transform axis.\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;
|
2016-03-13 03:49:26 +13:00
|
|
|
char keytype = BEZT_KEYTYPE_KEYFRAME; /* XXX: Expose this as a one-off option... */
|
2012-12-23 13:58:42 +00:00
|
|
|
int options = 0;
|
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:33:25 +11:00
|
|
|
if (pyrna_struct_keyframe_parse(
|
|
|
|
&self->ptr, args, kw,
|
|
|
|
"s|ifsO!:bpy_struct.keyframe_insert()", "bpy_struct.keyframe_insert()",
|
|
|
|
&path_full, &index, &cfra, &group_name, &options) == -1)
|
2011-04-30 13:58:31 +00:00
|
|
|
{
|
2011-03-02 04:51:43 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2016-12-28 23:20:25 +13:00
|
|
|
else if (self->ptr.type == &RNA_NlaStrip) {
|
|
|
|
/* 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.
|
|
|
|
*/
|
WIP COW Fix: Insert keyframe operators/api now queries depsgraph for evaluated data
When using copy on write, insert keyframe operators were reading from old
bmain data instead of COW data. This meant that inserting keyframes would
often read old/stale data, resulting in invalid keyframes getting created
(e.g. from last transform operation, instead of actual current state).
This commit makes it so that keyframing operators will ask depsgraph for
the evaluated copy of the data, so that it can read values from that. It
introduces a new function - `DEG_get_evaluated_rna_pointer()`, which when
working correctly/fully, should work just like the other `DEG_get_evaluated_*()`
functions, except it lets you pass in an RNA Pointer.
However, currently, this is only done for Pose Bones (as a dirty hack, since this
is an important/pivotal requirement for production) and/or datablock
properties directly (since we can just use the DEG_get_evaluated_id() directly).
on the datablock.
Committing to a branch for now as this all needs more testing. More work to come
later at a more sane time of day!
2018-05-18 20:36:48 +02:00
|
|
|
struct Depsgraph *depsgraph = CTX_data_depsgraph(BPy_GetContext());
|
2016-12-28 23:20:25 +13:00
|
|
|
ReportList reports;
|
|
|
|
short result = 0;
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2016-12-28 23:20:25 +13:00
|
|
|
PointerRNA ptr = self->ptr;
|
|
|
|
PropertyRNA *prop = NULL;
|
|
|
|
const char *prop_name;
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2016-12-28 23:20:25 +13:00
|
|
|
BKE_reports_init(&reports, RPT_STORE);
|
2018-06-04 08:54:17 +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);
|
|
|
|
}
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2016-12-28 23:20:25 +13:00
|
|
|
if (prop) {
|
|
|
|
NlaStrip *strip = (NlaStrip *)ptr.data;
|
|
|
|
FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2018-11-12 19:41:53 +03:00
|
|
|
result = insert_keyframe_direct(depsgraph, &reports, ptr, prop, fcu, cfra, 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);
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2016-12-28 23:20:25 +13:00
|
|
|
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
|
|
|
|
return NULL;
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2016-12-28 23:20:25 +13:00
|
|
|
return PyBool_FromLong(result);
|
|
|
|
}
|
2011-03-02 04:51:43 +00:00
|
|
|
else {
|
2018-06-22 11:37:47 +02:00
|
|
|
ID *id = self->ptr.id.data;
|
WIP COW Fix: Insert keyframe operators/api now queries depsgraph for evaluated data
When using copy on write, insert keyframe operators were reading from old
bmain data instead of COW data. This meant that inserting keyframes would
often read old/stale data, resulting in invalid keyframes getting created
(e.g. from last transform operation, instead of actual current state).
This commit makes it so that keyframing operators will ask depsgraph for
the evaluated copy of the data, so that it can read values from that. It
introduces a new function - `DEG_get_evaluated_rna_pointer()`, which when
working correctly/fully, should work just like the other `DEG_get_evaluated_*()`
functions, except it lets you pass in an RNA Pointer.
However, currently, this is only done for Pose Bones (as a dirty hack, since this
is an important/pivotal requirement for production) and/or datablock
properties directly (since we can just use the DEG_get_evaluated_id() directly).
on the datablock.
Committing to a branch for now as this all needs more testing. More work to come
later at a more sane time of day!
2018-05-18 20:36:48 +02:00
|
|
|
struct Depsgraph *depsgraph = CTX_data_depsgraph(BPy_GetContext());
|
2011-03-02 04:51:43 +00:00
|
|
|
ReportList reports;
|
2016-12-28 23:20:25 +13:00
|
|
|
short result;
|
2011-03-02 04:51:43 +00:00
|
|
|
|
|
|
|
BKE_reports_init(&reports, RPT_STORE);
|
|
|
|
|
2018-11-09 10:44:02 -02:00
|
|
|
BLI_assert(BKE_id_is_in_global_main(id));
|
2018-11-12 19:41:53 +03:00
|
|
|
result = insert_keyframe(G_MAIN, depsgraph, &reports, id, NULL, group_name, path_full, index, cfra, keytype, NULL, options);
|
2011-03-02 04:51:43 +00:00
|
|
|
MEM_freeN((void *)path_full);
|
|
|
|
|
2013-01-07 05:26:12 +00:00
|
|
|
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
|
2011-03-02 04:51:43 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return PyBool_FromLong(result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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"
|
|
|
|
" :return: Success of keyframe deleation.\n"
|
|
|
|
" :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;
|
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
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (pyrna_struct_keyframe_parse(&self->ptr, args, kw,
|
2012-12-23 13:58:42 +00: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-04-30 13:58:31 +00:00
|
|
|
{
|
2011-03-02 04:51:43 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2016-12-28 23:27:46 +13:00
|
|
|
else if (self->ptr.type == &RNA_NlaStrip) {
|
|
|
|
/* 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;
|
|
|
|
short result = 0;
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2016-12-28 23:27:46 +13:00
|
|
|
PointerRNA ptr = self->ptr;
|
|
|
|
PropertyRNA *prop = NULL;
|
|
|
|
const char *prop_name;
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2016-12-28 23:27:46 +13:00
|
|
|
BKE_reports_init(&reports, RPT_STORE);
|
2018-06-04 08:54:17 +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);
|
|
|
|
}
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2016-12-28 23:27:46 +13:00
|
|
|
if (prop) {
|
|
|
|
ID *id = ptr.id.data;
|
|
|
|
NlaStrip *strip = (NlaStrip *)ptr.data;
|
|
|
|
FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2016-12-28 23:27:46 +13:00
|
|
|
BLI_assert(fcu != NULL); /* NOTE: This should be true, or else we wouldn't be able to get here */
|
2018-06-04 08:54:17 +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, BKE_idcode_to_name(GS(id->name)), 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;
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2016-12-28 23:27:46 +13:00
|
|
|
/* try to find index of beztriple to get rid of */
|
|
|
|
i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found);
|
|
|
|
if (found) {
|
|
|
|
/* delete the key at the index (will sanity check + do recalc afterwards) */
|
|
|
|
delete_fcurve_key(fcu, i, 1);
|
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full);
|
|
|
|
}
|
|
|
|
MEM_freeN((void *)path_full);
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2016-12-28 23:27:46 +13:00
|
|
|
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
|
|
|
|
return NULL;
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2016-12-28 23:27:46 +13:00
|
|
|
return PyBool_FromLong(result);
|
|
|
|
}
|
2011-03-02 04:51:43 +00:00
|
|
|
else {
|
|
|
|
short result;
|
|
|
|
ReportList reports;
|
|
|
|
|
|
|
|
BKE_reports_init(&reports, RPT_STORE);
|
|
|
|
|
2018-10-22 17:13:19 +02:00
|
|
|
result = delete_keyframe(G.main, &reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0);
|
2011-03-02 04:51:43 +00:00
|
|
|
MEM_freeN((void *)path_full);
|
|
|
|
|
2013-01-07 05:26:12 +00:00
|
|
|
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
|
2011-03-02 04:51:43 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return PyBool_FromLong(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
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
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "s|i:driver_add", &path, &index))
|
|
|
|
return NULL;
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
else {
|
2011-12-26 12:26:11 +00:00
|
|
|
PyObject *ret = NULL;
|
2011-03-02 04:51:43 +00:00
|
|
|
ReportList reports;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
BKE_reports_init(&reports, RPT_STORE);
|
|
|
|
|
2018-06-04 08:54:17 +02:00
|
|
|
result = ANIM_add_driver(&reports, (ID *)self->ptr.id.data, path_full, index,
|
Tweaks to New Driver creation behaviour
* 'Show Debug' now enabled for all newly created drivers. For most users, it is
useful to be able to see this to help figure out what's going on
* Removed failed experiment of creating new drivers with Generator FModifiers. I
had hoped that this would make it easier to create drivers that doubled or
halved the input values, but that has proved to not be the case, and instead
made harder for most users to set things up (as they'd have to remove these
first).
Now, when adding drivers from the UI, these get created with two keyframes (at
(0,0) and (1,1) for a 1-1 mapping), which can be easily tweaked normally.
However, for backwards compatability of scripts (notably rigify, and perhaps
some others out there), when creating drivers from scripts, they will still get
created with Generator FModifiers for now. We can review this situation again
for 2.7, but for now it seems ok.
2013-09-03 00:28:23 +00:00
|
|
|
CREATEDRIVER_WITH_FMODIFIER, DRIVER_TYPE_PYTHON);
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2013-01-07 05:26:12 +00:00
|
|
|
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
|
2011-03-02 04:51:43 +00:00
|
|
|
return NULL;
|
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (result) {
|
2011-12-26 12:26:11 +00:00
|
|
|
ID *id = self->ptr.id.data;
|
|
|
|
AnimData *adt = BKE_animdata_from_id(id);
|
2011-03-02 04:51:43 +00:00
|
|
|
FCurve *fcu;
|
|
|
|
|
|
|
|
PointerRNA tptr;
|
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (index == -1) { /* all, use a list */
|
2011-12-26 12:26:11 +00:00
|
|
|
int i = 0;
|
|
|
|
ret = PyList_New(0);
|
|
|
|
while ((fcu = list_find_fcurve(&adt->drivers, path_full, i++))) {
|
2011-03-02 04:51:43 +00:00
|
|
|
RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
|
2015-01-06 17:39:47 +11:00
|
|
|
PyList_APPEND(ret, pyrna_struct_CreatePyObject(&tptr));
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2011-12-26 12:26:11 +00:00
|
|
|
fcu = list_find_fcurve(&adt->drivers, path_full, index);
|
2011-03-02 04:51:43 +00:00
|
|
|
RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
|
2011-12-26 12:26:11 +00:00
|
|
|
ret = pyrna_struct_CreatePyObject(&tptr);
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2012-03-26 20:41:54 +00:00
|
|
|
WM_event_add_notifier(BPy_GetContext(), NC_ANIMATION | ND_FCURVES_ORDER, NULL);
|
2011-03-02 04:51:43 +00: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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
short result;
|
|
|
|
ReportList reports;
|
|
|
|
|
|
|
|
BKE_reports_init(&reports, RPT_STORE);
|
|
|
|
|
2011-12-26 12:26:11 +00:00
|
|
|
result = ANIM_remove_driver(&reports, (ID *)self->ptr.id.data, path_full, index, 0);
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2019-01-07 15:27:59 +11:00
|
|
|
if (path != path_full) {
|
|
|
|
MEM_freeN((void *)path_full);
|
|
|
|
}
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2013-01-07 05:26:12 +00:00
|
|
|
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
|
2011-03-02 04:51:43 +00:00
|
|
|
return NULL;
|
2018-06-04 08:54:17 +02:00
|
|
|
|
2012-03-26 20:41:54 +00:00
|
|
|
WM_event_add_notifier(BPy_GetContext(), NC_ANIMATION | ND_FCURVES_ORDER, NULL);
|
2011-03-02 04:51:43 +00:00
|
|
|
|
|
|
|
return PyBool_FromLong(result);
|
|
|
|
}
|
|
|
|
}
|