2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup pythonintern
|
2011-11-05 08:21:12 +00:00
|
|
|
*
|
2023-07-31 11:50:54 +10:00
|
|
|
* This file defines the animation related methods used in `bpy_rna.cc`.
|
2011-03-02 04:51:43 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <Python.h>
|
2023-07-21 16:05:33 +10:00
|
|
|
#include <cfloat> /* FLT_MAX */
|
2011-03-02 04:51:43 +00:00
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
|
|
#include "BLI_string.h"
|
2023-10-18 17:15:30 +02:00
|
|
|
#include "BLI_string_utils.hh"
|
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
|
|
|
|
2023-08-05 02:57:52 +02:00
|
|
|
#include "ED_keyframing.hh"
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2023-10-12 12:46:47 +02:00
|
|
|
#include "ANIM_keyframing.hh"
|
|
|
|
|
|
2024-02-28 11:51:03 +01:00
|
|
|
#include "BKE_anim_data.hh"
|
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"
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_context.hh"
|
2024-03-05 18:39:08 +01:00
|
|
|
#include "BKE_fcurve.hh"
|
2024-02-10 18:25:14 +01:00
|
|
|
#include "BKE_global.hh"
|
2024-01-20 19:17:36 +01:00
|
|
|
#include "BKE_idtype.hh"
|
2024-01-15 12:44:04 -05:00
|
|
|
#include "BKE_lib_id.hh"
|
2024-02-10 18:34:29 +01:00
|
|
|
#include "BKE_report.hh"
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2023-08-10 22:40:27 +02:00
|
|
|
#include "RNA_access.hh"
|
|
|
|
|
#include "RNA_enum_types.hh"
|
|
|
|
|
#include "RNA_path.hh"
|
2024-07-10 18:30:02 +02:00
|
|
|
#include "RNA_prototypes.hh"
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2023-08-04 23:11:22 +02:00
|
|
|
#include "WM_api.hh"
|
|
|
|
|
#include "WM_types.hh"
|
2011-05-08 05:41:57 +00:00
|
|
|
|
2024-09-24 15:25:36 +02:00
|
|
|
#include "bpy_capi_utils.hh"
|
2024-09-24 11:30:38 +02:00
|
|
|
#include "bpy_rna.hh"
|
|
|
|
|
#include "bpy_rna_anim.hh"
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2024-09-24 15:25:36 +02:00
|
|
|
#include "../generic/py_capi_rna.hh"
|
|
|
|
|
#include "../generic/python_utildefines.hh"
|
2015-01-06 17:39:47 +11:00
|
|
|
|
2023-09-22 03:18:17 +02:00
|
|
|
#include "DEG_depsgraph.hh"
|
|
|
|
|
#include "DEG_depsgraph_build.hh"
|
2019-04-26 15:25:41 +02:00
|
|
|
|
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
|
|
|
|
2023-07-21 02:18:59 +02:00
|
|
|
if (ptr->data == nullptr) {
|
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) {
|
2023-07-21 02:18:59 +02:00
|
|
|
prop = nullptr;
|
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
|
|
|
|
2023-07-21 02:18:59 +02:00
|
|
|
if (prop == nullptr) {
|
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 {
|
2024-01-31 17:08:09 +01:00
|
|
|
const std::optional<std::string> path_full = RNA_path_from_ID_to_property(&r_ptr, prop);
|
|
|
|
|
*r_path_full = path_full ? BLI_strdup(path_full->c_str()) : nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-21 02:18:59 +02:00
|
|
|
if (*r_path_full == nullptr) {
|
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
|
|
|
{
|
2023-07-21 02:18:59 +02:00
|
|
|
return pyrna_struct_anim_args_parse_ex(ptr, error_prefix, path, r_path_full, r_index, nullptr);
|
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
|
|
|
|
2024-01-31 17:08:09 +01:00
|
|
|
const std::optional<std::string> path_prefix = RNA_path_from_ID_to_struct(ptr);
|
|
|
|
|
if (!path_prefix) {
|
2020-08-07 12:41:06 +02:00
|
|
|
PyErr_Format(PyExc_TypeError,
|
|
|
|
|
"%.200s could not make path for type %s",
|
|
|
|
|
error_prefix,
|
|
|
|
|
RNA_struct_identifier(ptr->type));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*path == '[') {
|
2024-01-31 17:08:09 +01:00
|
|
|
*r_path_full = BLI_string_joinN(path_prefix->c_str(), path);
|
2019-01-07 15:27:59 +11:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
else {
|
2024-01-31 17:08:09 +01:00
|
|
|
*r_path_full = BLI_string_join_by_sep_charN('.', path_prefix->c_str(), path);
|
2020-08-07 12:41:06 +02:00
|
|
|
}
|
|
|
|
|
|
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,
|
2024-04-12 16:27:30 +02:00
|
|
|
int *r_options,
|
|
|
|
|
eBezTriple_KeyframeType *r_keytype)
|
2011-03-02 04:51:43 +00:00
|
|
|
{
|
2024-04-12 16:27:30 +02:00
|
|
|
static const char *kwlist[] = {
|
|
|
|
|
"data_path", "index", "frame", "group", "options", "keytype", nullptr};
|
2023-07-21 02:18:59 +02:00
|
|
|
PyObject *pyoptions = nullptr;
|
2024-04-12 16:27:30 +02:00
|
|
|
char *keytype_name = nullptr;
|
2011-03-02 04:51:43 +00:00
|
|
|
const char *path;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-03 23:08:40 +10: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,
|
2024-04-12 16:27:30 +02:00
|
|
|
&pyoptions,
|
|
|
|
|
&keytype_name))
|
2019-01-07 15:27:59 +11:00
|
|
|
{
|
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 &&
|
2021-09-01 16:50:48 +10:00
|
|
|
(pyrna_enum_bitfield_from_set(
|
2023-08-25 12:57:52 +10:00
|
|
|
rna_enum_keying_flag_api_items, pyoptions, r_options, error_prefix) == -1))
|
2019-05-11 21:16:46 +03:00
|
|
|
{
|
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
|
|
|
|
2024-04-12 16:27:30 +02:00
|
|
|
if (r_keytype) {
|
|
|
|
|
int keytype_as_int = 0;
|
|
|
|
|
if (keytype_name && pyrna_enum_value_from_id(rna_enum_beztriple_keyframe_type_items,
|
|
|
|
|
keytype_name,
|
|
|
|
|
&keytype_as_int,
|
|
|
|
|
error_prefix) == -1)
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
*r_keytype = eBezTriple_KeyframeType(keytype_as_int);
|
|
|
|
|
}
|
|
|
|
|
|
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, "
|
2024-04-12 16:27:30 +02:00
|
|
|
"group=\"\", options=set(), keytype='KEYFRAME')\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"
|
2024-11-03 15:42:19 +11:00
|
|
|
" :type data_path: str\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"
|
2024-03-19 10:05:22 +01:00
|
|
|
" - ``INSERTKEY_XYZ_TO_RGB`` This flag is no longer in use, and is here so that code "
|
|
|
|
|
"that uses it doesn't break. The XYZ=RGB coloring is determined by the animation "
|
|
|
|
|
"preferences.\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"
|
2024-11-03 15:42:19 +11:00
|
|
|
" :type options: set[str]\n"
|
2024-04-12 16:27:30 +02:00
|
|
|
" :arg keytype: Type of the key: 'KEYFRAME', 'BREAKDOWN', 'MOVING_HOLD', 'EXTREME', "
|
|
|
|
|
"'JITTER', or 'GENERATED'\n"
|
2024-11-03 15:42:19 +11:00
|
|
|
" :type keytype: str\n"
|
2011-03-02 04:51:43 +00:00
|
|
|
" :return: Success of keyframe insertion.\n"
|
2024-11-03 15:42:19 +11:00
|
|
|
" :rtype: bool\n";
|
2011-03-02 04:51:43 +00:00
|
|
|
PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyObject *kw)
|
|
|
|
|
{
|
2024-04-23 10:10:23 +02:00
|
|
|
using namespace blender::animrig;
|
2011-03-02 04:51:43 +00:00
|
|
|
/* args, pyrna_struct_keyframe_parse handles these */
|
2023-07-21 02:18:59 +02:00
|
|
|
const char *path_full = nullptr;
|
2011-12-26 12:26:11 +00:00
|
|
|
int index = -1;
|
|
|
|
|
float cfra = FLT_MAX;
|
2023-07-21 02:18:59 +02:00
|
|
|
const char *group_name = nullptr;
|
2024-04-12 16:27:30 +02:00
|
|
|
eBezTriple_KeyframeType keytype = BEZT_KEYTYPE_KEYFRAME;
|
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
|
|
|
|
RNA: Make the `PointerRNA` struct non-trivial.
For now, PointerRNA is made non-trivial by giving explicit default
values to its members.
Besides of BPY python binding code, the change is relatively trivial.
The main change (besides the creation/deletion part) is the replacement
of `memset` by zero-initialized assignment (using `{}`).
makesrna required changes are quite small too.
The big piece of this PR is the refactor of the BPY RNA code.
It essentially brings back allocation and deletion of the BPy_StructRNA,
BPy_Pointer etc. python objects into 'cannonical process', using `__new__`,
and `__init__` callbacks (and there matching CAPI functions).
Existing code was doing very low-level manipulations to create these
data, which is not really easy to understand, and AFAICT incompatible
with handling C++ data that needs to be constructed and destructed.
Unfortunately, similar change in destruction code (using `__del__` and
matching `tp_finalize` CAPI callback) is not possible, because of technical
low-level implementation details in CPython (see [1] for details).
`std::optional` pointer management is used to encapsulate PointerRNA
data. This allows to keep control on _when_ actual RNA creation is done,
and to have a safe destruction in `tp_dealloc` callbacks.
Note that a critical change in Blender's Python API will be that classes
inherinting from `bpy_struct` etc. will now have to properly call the
base class `__new__` and/or `__init__`if they define them.
Implements #122431.
[1] https://discuss.python.org/t/cpython-usage-of-tp-finalize-in-c-defined-static-types-with-no-custom-tp-dealloc/64100
2024-10-30 15:08:37 +01:00
|
|
|
if (pyrna_struct_keyframe_parse(&self->ptr.value(),
|
2019-01-07 15:33:25 +11:00
|
|
|
args,
|
|
|
|
|
kw,
|
2024-04-12 16:27:30 +02:00
|
|
|
"s|$ifsO!s:bpy_struct.keyframe_insert()",
|
2019-01-07 15:33:25 +11:00
|
|
|
"bpy_struct.keyframe_insert()",
|
|
|
|
|
&path_full,
|
|
|
|
|
&index,
|
|
|
|
|
&cfra,
|
|
|
|
|
&group_name,
|
2024-04-12 16:27:30 +02:00
|
|
|
&options,
|
|
|
|
|
&keytype) == -1)
|
2019-01-07 15:33:25 +11:00
|
|
|
{
|
2023-07-21 02:18:59 +02:00
|
|
|
return nullptr;
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
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
|
|
|
|
2021-09-02 11:41:01 +10:00
|
|
|
ReportList reports;
|
|
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
|
|
BKE_reports_init(&reports, RPT_STORE);
|
|
|
|
|
|
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.
|
|
|
|
|
*
|
2024-01-18 15:40:07 +01:00
|
|
|
* The depsgraph is only used for evaluating the NLA so this might not be needed in the future.
|
|
|
|
|
*/
|
2020-10-15 18:20:15 +11:00
|
|
|
bContext *C = BPY_context_get();
|
2023-07-20 11:30:25 +10:00
|
|
|
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
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
|
|
|
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
|
|
|
|
|
cfra);
|
|
|
|
|
|
RNA: Make the `PointerRNA` struct non-trivial.
For now, PointerRNA is made non-trivial by giving explicit default
values to its members.
Besides of BPY python binding code, the change is relatively trivial.
The main change (besides the creation/deletion part) is the replacement
of `memset` by zero-initialized assignment (using `{}`).
makesrna required changes are quite small too.
The big piece of this PR is the refactor of the BPY RNA code.
It essentially brings back allocation and deletion of the BPy_StructRNA,
BPy_Pointer etc. python objects into 'cannonical process', using `__new__`,
and `__init__` callbacks (and there matching CAPI functions).
Existing code was doing very low-level manipulations to create these
data, which is not really easy to understand, and AFAICT incompatible
with handling C++ data that needs to be constructed and destructed.
Unfortunately, similar change in destruction code (using `__del__` and
matching `tp_finalize` CAPI callback) is not possible, because of technical
low-level implementation details in CPython (see [1] for details).
`std::optional` pointer management is used to encapsulate PointerRNA
data. This allows to keep control on _when_ actual RNA creation is done,
and to have a safe destruction in `tp_dealloc` callbacks.
Note that a critical change in Blender's Python API will be that classes
inherinting from `bpy_struct` etc. will now have to properly call the
base class `__new__` and/or `__init__`if they define them.
Implements #122431.
[1] https://discuss.python.org/t/cpython-usage-of-tp-finalize-in-c-defined-static-types-with-no-custom-tp-dealloc/64100
2024-10-30 15:08:37 +01:00
|
|
|
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.
|
|
|
|
|
*/
|
2019-04-17 06:17:24 +02:00
|
|
|
|
RNA: Make the `PointerRNA` struct non-trivial.
For now, PointerRNA is made non-trivial by giving explicit default
values to its members.
Besides of BPY python binding code, the change is relatively trivial.
The main change (besides the creation/deletion part) is the replacement
of `memset` by zero-initialized assignment (using `{}`).
makesrna required changes are quite small too.
The big piece of this PR is the refactor of the BPY RNA code.
It essentially brings back allocation and deletion of the BPy_StructRNA,
BPy_Pointer etc. python objects into 'cannonical process', using `__new__`,
and `__init__` callbacks (and there matching CAPI functions).
Existing code was doing very low-level manipulations to create these
data, which is not really easy to understand, and AFAICT incompatible
with handling C++ data that needs to be constructed and destructed.
Unfortunately, similar change in destruction code (using `__del__` and
matching `tp_finalize` CAPI callback) is not possible, because of technical
low-level implementation details in CPython (see [1] for details).
`std::optional` pointer management is used to encapsulate PointerRNA
data. This allows to keep control on _when_ actual RNA creation is done,
and to have a safe destruction in `tp_dealloc` callbacks.
Note that a critical change in Blender's Python API will be that classes
inherinting from `bpy_struct` etc. will now have to properly call the
base class `__new__` and/or `__init__`if they define them.
Implements #122431.
[1] https://discuss.python.org/t/cpython-usage-of-tp-finalize-in-c-defined-static-types-with-no-custom-tp-dealloc/64100
2024-10-30 15:08:37 +01:00
|
|
|
PointerRNA &ptr = *self->ptr;
|
2023-07-21 02:18:59 +02:00
|
|
|
PropertyRNA *prop = nullptr;
|
2016-12-28 23:20:25 +13:00
|
|
|
const char *prop_name;
|
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) {
|
2023-07-21 02:18:59 +02:00
|
|
|
NlaStrip *strip = static_cast<NlaStrip *>(ptr.data);
|
2020-06-05 09:30:15 +02:00
|
|
|
FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
|
2024-04-23 10:10:23 +02:00
|
|
|
result = insert_keyframe_direct(&reports,
|
|
|
|
|
ptr,
|
|
|
|
|
prop,
|
|
|
|
|
fcu,
|
|
|
|
|
&anim_eval_context,
|
|
|
|
|
eBezTriple_KeyframeType(keytype),
|
|
|
|
|
nullptr,
|
|
|
|
|
eInsertKeyFlags(options));
|
2016-12-28 23:20:25 +13:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full);
|
|
|
|
|
}
|
2021-09-02 11:41:01 +10:00
|
|
|
}
|
|
|
|
|
else {
|
RNA: Make the `PointerRNA` struct non-trivial.
For now, PointerRNA is made non-trivial by giving explicit default
values to its members.
Besides of BPY python binding code, the change is relatively trivial.
The main change (besides the creation/deletion part) is the replacement
of `memset` by zero-initialized assignment (using `{}`).
makesrna required changes are quite small too.
The big piece of this PR is the refactor of the BPY RNA code.
It essentially brings back allocation and deletion of the BPy_StructRNA,
BPy_Pointer etc. python objects into 'cannonical process', using `__new__`,
and `__init__` callbacks (and there matching CAPI functions).
Existing code was doing very low-level manipulations to create these
data, which is not really easy to understand, and AFAICT incompatible
with handling C++ data that needs to be constructed and destructed.
Unfortunately, similar change in destruction code (using `__del__` and
matching `tp_finalize` CAPI callback) is not possible, because of technical
low-level implementation details in CPython (see [1] for details).
`std::optional` pointer management is used to encapsulate PointerRNA
data. This allows to keep control on _when_ actual RNA creation is done,
and to have a safe destruction in `tp_dealloc` callbacks.
Note that a critical change in Blender's Python API will be that classes
inherinting from `bpy_struct` etc. will now have to properly call the
base class `__new__` and/or `__init__`if they define them.
Implements #122431.
[1] https://discuss.python.org/t/cpython-usage-of-tp-finalize-in-c-defined-static-types-with-no-custom-tp-dealloc/64100
2024-10-30 15:08:37 +01:00
|
|
|
BLI_assert(BKE_id_is_in_global_main(self->ptr->owner_id));
|
Refactor: combine insert_keyframe() and insert_key_rna() into a single function
The goal of this PR is to merge `insert_keyframe()` and `insert_key_rna()` into
a single function, `insert_keyframes()`, that fully accommodates the
functionality of both. This results in a bit of a mega function, which isn't
great, but it centralizes a lot of otherwise redundant keyframing code so it
only needs to be changed in one place in the future.
Future PRs can work to reduce the "mega" aspect of this function, stripping it
down to its core functionality and eliminating left over incidental redundancy
(e.g. passing both `scene_frame` and `anim_eval_context`).
As a wonderful side effect, this PR also makes layered action keyframing work in
most of the remaining places left over from #121661, such as buttons, the
dopesheet, the graph editor, etc.
Pull Request: https://projects.blender.org/blender/blender/pulls/122053
2024-06-11 16:42:55 +02:00
|
|
|
|
|
|
|
|
const std::optional<blender::StringRefNull> channel_group = group_name ?
|
|
|
|
|
std::optional(group_name) :
|
|
|
|
|
std::nullopt;
|
RNA: Make the `PointerRNA` struct non-trivial.
For now, PointerRNA is made non-trivial by giving explicit default
values to its members.
Besides of BPY python binding code, the change is relatively trivial.
The main change (besides the creation/deletion part) is the replacement
of `memset` by zero-initialized assignment (using `{}`).
makesrna required changes are quite small too.
The big piece of this PR is the refactor of the BPY RNA code.
It essentially brings back allocation and deletion of the BPy_StructRNA,
BPy_Pointer etc. python objects into 'cannonical process', using `__new__`,
and `__init__` callbacks (and there matching CAPI functions).
Existing code was doing very low-level manipulations to create these
data, which is not really easy to understand, and AFAICT incompatible
with handling C++ data that needs to be constructed and destructed.
Unfortunately, similar change in destruction code (using `__del__` and
matching `tp_finalize` CAPI callback) is not possible, because of technical
low-level implementation details in CPython (see [1] for details).
`std::optional` pointer management is used to encapsulate PointerRNA
data. This allows to keep control on _when_ actual RNA creation is done,
and to have a safe destruction in `tp_dealloc` callbacks.
Note that a critical change in Blender's Python API will be that classes
inherinting from `bpy_struct` etc. will now have to properly call the
base class `__new__` and/or `__init__`if they define them.
Implements #122431.
[1] https://discuss.python.org/t/cpython-usage-of-tp-finalize-in-c-defined-static-types-with-no-custom-tp-dealloc/64100
2024-10-30 15:08:37 +01:00
|
|
|
PointerRNA id_pointer = RNA_id_pointer_create(self->ptr->owner_id);
|
Refactor: combine insert_keyframe() and insert_key_rna() into a single function
The goal of this PR is to merge `insert_keyframe()` and `insert_key_rna()` into
a single function, `insert_keyframes()`, that fully accommodates the
functionality of both. This results in a bit of a mega function, which isn't
great, but it centralizes a lot of otherwise redundant keyframing code so it
only needs to be changed in one place in the future.
Future PRs can work to reduce the "mega" aspect of this function, stripping it
down to its core functionality and eliminating left over incidental redundancy
(e.g. passing both `scene_frame` and `anim_eval_context`).
As a wonderful side effect, this PR also makes layered action keyframing work in
most of the remaining places left over from #121661, such as buttons, the
dopesheet, the graph editor, etc.
Pull Request: https://projects.blender.org/blender/blender/pulls/122053
2024-06-11 16:42:55 +02:00
|
|
|
CombinedKeyingResult combined_result = insert_keyframes(G_MAIN,
|
2024-06-25 14:16:55 +02:00
|
|
|
&id_pointer,
|
Refactor: combine insert_keyframe() and insert_key_rna() into a single function
The goal of this PR is to merge `insert_keyframe()` and `insert_key_rna()` into
a single function, `insert_keyframes()`, that fully accommodates the
functionality of both. This results in a bit of a mega function, which isn't
great, but it centralizes a lot of otherwise redundant keyframing code so it
only needs to be changed in one place in the future.
Future PRs can work to reduce the "mega" aspect of this function, stripping it
down to its core functionality and eliminating left over incidental redundancy
(e.g. passing both `scene_frame` and `anim_eval_context`).
As a wonderful side effect, this PR also makes layered action keyframing work in
most of the remaining places left over from #121661, such as buttons, the
dopesheet, the graph editor, etc.
Pull Request: https://projects.blender.org/blender/blender/pulls/122053
2024-06-11 16:42:55 +02:00
|
|
|
channel_group,
|
|
|
|
|
{{path_full, {}, index}},
|
|
|
|
|
std::nullopt,
|
|
|
|
|
anim_eval_context,
|
|
|
|
|
eBezTriple_KeyframeType(keytype),
|
|
|
|
|
eInsertKeyFlags(options));
|
2024-04-23 10:10:23 +02:00
|
|
|
const int success_count = combined_result.get_count(SingleKeyingResult::SUCCESS);
|
|
|
|
|
if (success_count == 0) {
|
2024-06-11 11:11:16 +02:00
|
|
|
/* Ideally this would use the GUI presentation of RPT_ERROR, as the resulting pop-up has more
|
|
|
|
|
* vertical space than the single-line warning in the status bar. However, semantically these
|
|
|
|
|
* may not be errors at all, as skipping the keying of certain properties due to the 'only
|
|
|
|
|
* insert available' flag is not an error.
|
|
|
|
|
*
|
|
|
|
|
* Furthermore, using RPT_ERROR here would cause this function to raise a Python exception,
|
|
|
|
|
* rather than returning a boolean. */
|
|
|
|
|
combined_result.generate_reports(&reports, RPT_WARNING);
|
2024-04-23 10:10:23 +02:00
|
|
|
}
|
|
|
|
|
result = success_count != 0;
|
2016-12-28 23:20:25 +13:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-12 17:25:55 +02:00
|
|
|
MEM_freeN(path_full);
|
2020-08-07 12:41:06 +02:00
|
|
|
|
2024-06-11 11:11:16 +02:00
|
|
|
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, false) == -1) {
|
|
|
|
|
BKE_reports_free(&reports);
|
2023-07-21 02:18:59 +02:00
|
|
|
return nullptr;
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
2024-09-19 14:49:05 +10:00
|
|
|
BKE_report_print_level_set(&reports, G.quiet ? RPT_WARNING : RPT_DEBUG);
|
2024-06-11 11:11:16 +02:00
|
|
|
BPy_reports_write_stdout(&reports, nullptr);
|
|
|
|
|
BKE_reports_free(&reports);
|
2020-08-07 12:41:06 +02:00
|
|
|
|
2021-12-16 11:26:21 +01:00
|
|
|
if (result) {
|
2023-07-21 02:18:59 +02:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, nullptr);
|
2021-12-16 11:26:21 +01: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"
|
2024-11-03 15:42:19 +11:00
|
|
|
" :type data_path: str\n"
|
2011-03-02 04:51:43 +00:00
|
|
|
" :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"
|
2024-11-03 15:42:19 +11:00
|
|
|
" :rtype: bool\n";
|
2011-03-02 04:51:43 +00:00
|
|
|
PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyObject *kw)
|
|
|
|
|
{
|
|
|
|
|
/* args, pyrna_struct_keyframe_parse handles these */
|
2023-07-21 02:18:59 +02:00
|
|
|
const char *path_full = nullptr;
|
2011-12-26 12:26:11 +00:00
|
|
|
int index = -1;
|
|
|
|
|
float cfra = FLT_MAX;
|
2023-07-21 02:18:59 +02:00
|
|
|
const char *group_name = nullptr;
|
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
|
|
|
|
RNA: Make the `PointerRNA` struct non-trivial.
For now, PointerRNA is made non-trivial by giving explicit default
values to its members.
Besides of BPY python binding code, the change is relatively trivial.
The main change (besides the creation/deletion part) is the replacement
of `memset` by zero-initialized assignment (using `{}`).
makesrna required changes are quite small too.
The big piece of this PR is the refactor of the BPY RNA code.
It essentially brings back allocation and deletion of the BPy_StructRNA,
BPy_Pointer etc. python objects into 'cannonical process', using `__new__`,
and `__init__` callbacks (and there matching CAPI functions).
Existing code was doing very low-level manipulations to create these
data, which is not really easy to understand, and AFAICT incompatible
with handling C++ data that needs to be constructed and destructed.
Unfortunately, similar change in destruction code (using `__del__` and
matching `tp_finalize` CAPI callback) is not possible, because of technical
low-level implementation details in CPython (see [1] for details).
`std::optional` pointer management is used to encapsulate PointerRNA
data. This allows to keep control on _when_ actual RNA creation is done,
and to have a safe destruction in `tp_dealloc` callbacks.
Note that a critical change in Blender's Python API will be that classes
inherinting from `bpy_struct` etc. will now have to properly call the
base class `__new__` and/or `__init__`if they define them.
Implements #122431.
[1] https://discuss.python.org/t/cpython-usage-of-tp-finalize-in-c-defined-static-types-with-no-custom-tp-dealloc/64100
2024-10-30 15:08:37 +01:00
|
|
|
if (pyrna_struct_keyframe_parse(&self->ptr.value(),
|
2011-10-13 01:29:08 +00:00
|
|
|
args,
|
|
|
|
|
kw,
|
2024-04-12 16:27:30 +02:00
|
|
|
"s|$ifsOs!: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,
|
2024-04-12 16:27:30 +02:00
|
|
|
nullptr,
|
2023-07-21 02:18:59 +02:00
|
|
|
nullptr) == -1)
|
2012-12-23 13:58:42 +00:00
|
|
|
{
|
2023-07-21 02:18:59 +02:00
|
|
|
return nullptr;
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
2021-09-02 11:41:01 +10:00
|
|
|
|
|
|
|
|
ReportList reports;
|
|
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
|
|
BKE_reports_init(&reports, RPT_STORE);
|
|
|
|
|
|
RNA: Make the `PointerRNA` struct non-trivial.
For now, PointerRNA is made non-trivial by giving explicit default
values to its members.
Besides of BPY python binding code, the change is relatively trivial.
The main change (besides the creation/deletion part) is the replacement
of `memset` by zero-initialized assignment (using `{}`).
makesrna required changes are quite small too.
The big piece of this PR is the refactor of the BPY RNA code.
It essentially brings back allocation and deletion of the BPy_StructRNA,
BPy_Pointer etc. python objects into 'cannonical process', using `__new__`,
and `__init__` callbacks (and there matching CAPI functions).
Existing code was doing very low-level manipulations to create these
data, which is not really easy to understand, and AFAICT incompatible
with handling C++ data that needs to be constructed and destructed.
Unfortunately, similar change in destruction code (using `__del__` and
matching `tp_finalize` CAPI callback) is not possible, because of technical
low-level implementation details in CPython (see [1] for details).
`std::optional` pointer management is used to encapsulate PointerRNA
data. This allows to keep control on _when_ actual RNA creation is done,
and to have a safe destruction in `tp_dealloc` callbacks.
Note that a critical change in Blender's Python API will be that classes
inherinting from `bpy_struct` etc. will now have to properly call the
base class `__new__` and/or `__init__`if they define them.
Implements #122431.
[1] https://discuss.python.org/t/cpython-usage-of-tp-finalize-in-c-defined-static-types-with-no-custom-tp-dealloc/64100
2024-10-30 15:08:37 +01: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.
|
|
|
|
|
*/
|
2019-04-17 06:17:24 +02:00
|
|
|
|
RNA: Make the `PointerRNA` struct non-trivial.
For now, PointerRNA is made non-trivial by giving explicit default
values to its members.
Besides of BPY python binding code, the change is relatively trivial.
The main change (besides the creation/deletion part) is the replacement
of `memset` by zero-initialized assignment (using `{}`).
makesrna required changes are quite small too.
The big piece of this PR is the refactor of the BPY RNA code.
It essentially brings back allocation and deletion of the BPy_StructRNA,
BPy_Pointer etc. python objects into 'cannonical process', using `__new__`,
and `__init__` callbacks (and there matching CAPI functions).
Existing code was doing very low-level manipulations to create these
data, which is not really easy to understand, and AFAICT incompatible
with handling C++ data that needs to be constructed and destructed.
Unfortunately, similar change in destruction code (using `__del__` and
matching `tp_finalize` CAPI callback) is not possible, because of technical
low-level implementation details in CPython (see [1] for details).
`std::optional` pointer management is used to encapsulate PointerRNA
data. This allows to keep control on _when_ actual RNA creation is done,
and to have a safe destruction in `tp_dealloc` callbacks.
Note that a critical change in Blender's Python API will be that classes
inherinting from `bpy_struct` etc. will now have to properly call the
base class `__new__` and/or `__init__`if they define them.
Implements #122431.
[1] https://discuss.python.org/t/cpython-usage-of-tp-finalize-in-c-defined-static-types-with-no-custom-tp-dealloc/64100
2024-10-30 15:08:37 +01:00
|
|
|
PointerRNA ptr = *self->ptr;
|
2023-07-21 02:18:59 +02:00
|
|
|
PropertyRNA *prop = nullptr;
|
2016-12-28 23:27:46 +13:00
|
|
|
const char *prop_name;
|
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;
|
2023-07-21 02:18:59 +02:00
|
|
|
NlaStrip *strip = static_cast<NlaStrip *>(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. */
|
2023-07-21 02:18:59 +02:00
|
|
|
BLI_assert(fcu != nullptr);
|
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) */
|
2022-07-14 10:22:30 +02:00
|
|
|
BKE_fcurve_delete_key(fcu, i);
|
|
|
|
|
BKE_fcurve_handles_recalc(fcu);
|
2016-12-28 23:27:46 +13:00
|
|
|
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);
|
|
|
|
|
}
|
2021-09-02 11:41:01 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2024-07-26 13:29:25 +02:00
|
|
|
RNAPath rna_path = {path_full, std::nullopt, index};
|
|
|
|
|
if (index < 0) {
|
|
|
|
|
rna_path.index = std::nullopt;
|
|
|
|
|
}
|
2023-10-12 12:46:47 +02:00
|
|
|
result = (blender::animrig::delete_keyframe(
|
RNA: Make the `PointerRNA` struct non-trivial.
For now, PointerRNA is made non-trivial by giving explicit default
values to its members.
Besides of BPY python binding code, the change is relatively trivial.
The main change (besides the creation/deletion part) is the replacement
of `memset` by zero-initialized assignment (using `{}`).
makesrna required changes are quite small too.
The big piece of this PR is the refactor of the BPY RNA code.
It essentially brings back allocation and deletion of the BPy_StructRNA,
BPy_Pointer etc. python objects into 'cannonical process', using `__new__`,
and `__init__` callbacks (and there matching CAPI functions).
Existing code was doing very low-level manipulations to create these
data, which is not really easy to understand, and AFAICT incompatible
with handling C++ data that needs to be constructed and destructed.
Unfortunately, similar change in destruction code (using `__del__` and
matching `tp_finalize` CAPI callback) is not possible, because of technical
low-level implementation details in CPython (see [1] for details).
`std::optional` pointer management is used to encapsulate PointerRNA
data. This allows to keep control on _when_ actual RNA creation is done,
and to have a safe destruction in `tp_dealloc` callbacks.
Note that a critical change in Blender's Python API will be that classes
inherinting from `bpy_struct` etc. will now have to properly call the
base class `__new__` and/or `__init__`if they define them.
Implements #122431.
[1] https://discuss.python.org/t/cpython-usage-of-tp-finalize-in-c-defined-static-types-with-no-custom-tp-dealloc/64100
2024-10-30 15:08:37 +01:00
|
|
|
G.main, &reports, self->ptr->owner_id, rna_path, cfra) != 0);
|
2016-12-28 23:27:46 +13:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-12 17:25:55 +02:00
|
|
|
MEM_freeN(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) {
|
2023-07-21 02:18:59 +02:00
|
|
|
return nullptr;
|
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"
|
2024-11-03 15:42:19 +11:00
|
|
|
" :type path: str\n"
|
2011-03-02 04:51:43 +00:00
|
|
|
" :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"
|
2024-11-03 15:42:19 +11:00
|
|
|
" :return: The driver added or a list of drivers when index is -1.\n"
|
|
|
|
|
" :rtype: :class:`bpy.types.FCurve` | list[:class:`bpy.types.FCurve`]\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)) {
|
2023-07-21 02:18:59 +02:00
|
|
|
return nullptr;
|
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(
|
RNA: Make the `PointerRNA` struct non-trivial.
For now, PointerRNA is made non-trivial by giving explicit default
values to its members.
Besides of BPY python binding code, the change is relatively trivial.
The main change (besides the creation/deletion part) is the replacement
of `memset` by zero-initialized assignment (using `{}`).
makesrna required changes are quite small too.
The big piece of this PR is the refactor of the BPY RNA code.
It essentially brings back allocation and deletion of the BPy_StructRNA,
BPy_Pointer etc. python objects into 'cannonical process', using `__new__`,
and `__init__` callbacks (and there matching CAPI functions).
Existing code was doing very low-level manipulations to create these
data, which is not really easy to understand, and AFAICT incompatible
with handling C++ data that needs to be constructed and destructed.
Unfortunately, similar change in destruction code (using `__del__` and
matching `tp_finalize` CAPI callback) is not possible, because of technical
low-level implementation details in CPython (see [1] for details).
`std::optional` pointer management is used to encapsulate PointerRNA
data. This allows to keep control on _when_ actual RNA creation is done,
and to have a safe destruction in `tp_dealloc` callbacks.
Note that a critical change in Blender's Python API will be that classes
inherinting from `bpy_struct` etc. will now have to properly call the
base class `__new__` and/or `__init__`if they define them.
Implements #122431.
[1] https://discuss.python.org/t/cpython-usage-of-tp-finalize-in-c-defined-static-types-with-no-custom-tp-dealloc/64100
2024-10-30 15:08:37 +01:00
|
|
|
&self->ptr.value(), "bpy_struct.driver_add():", path, &path_full, &index) == -1)
|
2019-01-07 15:27:59 +11:00
|
|
|
{
|
2023-07-21 02:18:59 +02:00
|
|
|
return nullptr;
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-21 02:18:59 +02:00
|
|
|
PyObject *ret = nullptr;
|
2020-08-07 12:41:06 +02:00
|
|
|
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,
|
RNA: Make the `PointerRNA` struct non-trivial.
For now, PointerRNA is made non-trivial by giving explicit default
values to its members.
Besides of BPY python binding code, the change is relatively trivial.
The main change (besides the creation/deletion part) is the replacement
of `memset` by zero-initialized assignment (using `{}`).
makesrna required changes are quite small too.
The big piece of this PR is the refactor of the BPY RNA code.
It essentially brings back allocation and deletion of the BPy_StructRNA,
BPy_Pointer etc. python objects into 'cannonical process', using `__new__`,
and `__init__` callbacks (and there matching CAPI functions).
Existing code was doing very low-level manipulations to create these
data, which is not really easy to understand, and AFAICT incompatible
with handling C++ data that needs to be constructed and destructed.
Unfortunately, similar change in destruction code (using `__del__` and
matching `tp_finalize` CAPI callback) is not possible, because of technical
low-level implementation details in CPython (see [1] for details).
`std::optional` pointer management is used to encapsulate PointerRNA
data. This allows to keep control on _when_ actual RNA creation is done,
and to have a safe destruction in `tp_dealloc` callbacks.
Note that a critical change in Blender's Python API will be that classes
inherinting from `bpy_struct` etc. will now have to properly call the
base class `__new__` and/or `__init__`if they define them.
Implements #122431.
[1] https://discuss.python.org/t/cpython-usage-of-tp-finalize-in-c-defined-static-types-with-no-custom-tp-dealloc/64100
2024-10-30 15:08:37 +01:00
|
|
|
self->ptr->owner_id,
|
2020-08-07 12:41:06 +02:00
|
|
|
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) {
|
2023-07-21 02:18:59 +02:00
|
|
|
return nullptr;
|
2020-08-07 12:41:06 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
if (result) {
|
RNA: Make the `PointerRNA` struct non-trivial.
For now, PointerRNA is made non-trivial by giving explicit default
values to its members.
Besides of BPY python binding code, the change is relatively trivial.
The main change (besides the creation/deletion part) is the replacement
of `memset` by zero-initialized assignment (using `{}`).
makesrna required changes are quite small too.
The big piece of this PR is the refactor of the BPY RNA code.
It essentially brings back allocation and deletion of the BPy_StructRNA,
BPy_Pointer etc. python objects into 'cannonical process', using `__new__`,
and `__init__` callbacks (and there matching CAPI functions).
Existing code was doing very low-level manipulations to create these
data, which is not really easy to understand, and AFAICT incompatible
with handling C++ data that needs to be constructed and destructed.
Unfortunately, similar change in destruction code (using `__del__` and
matching `tp_finalize` CAPI callback) is not possible, because of technical
low-level implementation details in CPython (see [1] for details).
`std::optional` pointer management is used to encapsulate PointerRNA
data. This allows to keep control on _when_ actual RNA creation is done,
and to have a safe destruction in `tp_dealloc` callbacks.
Note that a critical change in Blender's Python API will be that classes
inherinting from `bpy_struct` etc. will now have to properly call the
base class `__new__` and/or `__init__`if they define them.
Implements #122431.
[1] https://discuss.python.org/t/cpython-usage-of-tp-finalize-in-c-defined-static-types-with-no-custom-tp-dealloc/64100
2024-10-30 15:08:37 +01:00
|
|
|
ID *id = self->ptr->owner_id;
|
2020-08-07 12:41:06 +02:00
|
|
|
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++))) {
|
2025-01-24 16:45:32 +01:00
|
|
|
tptr = RNA_pointer_create_discrete(id, &RNA_FCurve, fcu);
|
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);
|
2025-01-24 16:45:32 +01:00
|
|
|
tptr = RNA_pointer_create_discrete(id, &RNA_FCurve, fcu);
|
2020-08-07 12:41:06 +02:00
|
|
|
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();
|
2023-07-21 02:18:59 +02:00
|
|
|
WM_event_add_notifier(BPY_context_get(), NC_ANIMATION | ND_FCURVES_ORDER, nullptr);
|
2024-02-19 15:54:08 +01:00
|
|
|
DEG_id_tag_update(id, ID_RECALC_SYNC_TO_EVAL);
|
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 {
|
2021-07-23 16:56:00 +10:00
|
|
|
/* XXX: should be handled by reports. */
|
2020-08-07 12:41:06 +02:00
|
|
|
PyErr_SetString(PyExc_TypeError,
|
|
|
|
|
"bpy_struct.driver_add(): failed because of an internal error");
|
2023-07-21 02:18:59 +02:00
|
|
|
return nullptr;
|
2020-08-07 12:41:06 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-12 17:25:55 +02:00
|
|
|
MEM_freeN(path_full);
|
2020-08-07 12:41:06 +02:00
|
|
|
|
|
|
|
|
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"
|
2024-11-03 15:42:19 +11:00
|
|
|
" :type path: str\n"
|
2011-03-02 04:51:43 +00:00
|
|
|
" :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"
|
2024-11-03 15:42:19 +11:00
|
|
|
" :rtype: bool\n";
|
2011-03-02 04:51:43 +00:00
|
|
|
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)) {
|
2023-07-21 02:18:59 +02:00
|
|
|
return nullptr;
|
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(
|
RNA: Make the `PointerRNA` struct non-trivial.
For now, PointerRNA is made non-trivial by giving explicit default
values to its members.
Besides of BPY python binding code, the change is relatively trivial.
The main change (besides the creation/deletion part) is the replacement
of `memset` by zero-initialized assignment (using `{}`).
makesrna required changes are quite small too.
The big piece of this PR is the refactor of the BPY RNA code.
It essentially brings back allocation and deletion of the BPy_StructRNA,
BPy_Pointer etc. python objects into 'cannonical process', using `__new__`,
and `__init__` callbacks (and there matching CAPI functions).
Existing code was doing very low-level manipulations to create these
data, which is not really easy to understand, and AFAICT incompatible
with handling C++ data that needs to be constructed and destructed.
Unfortunately, similar change in destruction code (using `__del__` and
matching `tp_finalize` CAPI callback) is not possible, because of technical
low-level implementation details in CPython (see [1] for details).
`std::optional` pointer management is used to encapsulate PointerRNA
data. This allows to keep control on _when_ actual RNA creation is done,
and to have a safe destruction in `tp_dealloc` callbacks.
Note that a critical change in Blender's Python API will be that classes
inherinting from `bpy_struct` etc. will now have to properly call the
base class `__new__` and/or `__init__`if they define them.
Implements #122431.
[1] https://discuss.python.org/t/cpython-usage-of-tp-finalize-in-c-defined-static-types-with-no-custom-tp-dealloc/64100
2024-10-30 15:08:37 +01:00
|
|
|
&self->ptr.value(), "bpy_struct.driver_remove():", path, &path_full, &index) == -1)
|
2019-01-07 15:27:59 +11:00
|
|
|
{
|
2023-07-21 02:18:59 +02:00
|
|
|
return nullptr;
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
RNA: Make the `PointerRNA` struct non-trivial.
For now, PointerRNA is made non-trivial by giving explicit default
values to its members.
Besides of BPY python binding code, the change is relatively trivial.
The main change (besides the creation/deletion part) is the replacement
of `memset` by zero-initialized assignment (using `{}`).
makesrna required changes are quite small too.
The big piece of this PR is the refactor of the BPY RNA code.
It essentially brings back allocation and deletion of the BPy_StructRNA,
BPy_Pointer etc. python objects into 'cannonical process', using `__new__`,
and `__init__` callbacks (and there matching CAPI functions).
Existing code was doing very low-level manipulations to create these
data, which is not really easy to understand, and AFAICT incompatible
with handling C++ data that needs to be constructed and destructed.
Unfortunately, similar change in destruction code (using `__del__` and
matching `tp_finalize` CAPI callback) is not possible, because of technical
low-level implementation details in CPython (see [1] for details).
`std::optional` pointer management is used to encapsulate PointerRNA
data. This allows to keep control on _when_ actual RNA creation is done,
and to have a safe destruction in `tp_dealloc` callbacks.
Note that a critical change in Blender's Python API will be that classes
inherinting from `bpy_struct` etc. will now have to properly call the
base class `__new__` and/or `__init__`if they define them.
Implements #122431.
[1] https://discuss.python.org/t/cpython-usage-of-tp-finalize-in-c-defined-static-types-with-no-custom-tp-dealloc/64100
2024-10-30 15:08:37 +01:00
|
|
|
result = ANIM_remove_driver(self->ptr->owner_id, path_full, index);
|
2011-03-02 04:51:43 +00:00
|
|
|
|
2020-08-07 12:41:06 +02:00
|
|
|
if (path != path_full) {
|
2025-04-12 17:25:55 +02:00
|
|
|
MEM_freeN(path_full);
|
2020-08-07 12:41:06 +02:00
|
|
|
}
|
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) {
|
2023-07-21 02:18:59 +02:00
|
|
|
return nullptr;
|
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();
|
2023-07-21 02:18:59 +02:00
|
|
|
WM_event_add_notifier(context, NC_ANIMATION | ND_FCURVES_ORDER, nullptr);
|
2025-05-06 17:46:52 +02:00
|
|
|
DEG_id_tag_update(self->ptr->owner_id, ID_RECALC_ANIMATION);
|
2020-08-07 12:41:06 +02:00
|
|
|
DEG_relations_tag_update(CTX_data_main(context));
|
|
|
|
|
|
|
|
|
|
return PyBool_FromLong(result);
|
2011-03-02 04:51:43 +00:00
|
|
|
}
|