diff --git a/source/blender/python/intern/bpy_rna.cmakesdna/DNA_defaults.h b/source/blender/python/intern/bpy_rna.cmakesdna/DNA_defaults.h
index 5bd4d86d92a..efd7a4d8adeef7f573e7a8..b2d38bc849c 100644
--- a/source/blender/python/intern/bpy_rna.cmakesdna/DNA_defaults.h
+++ b/source/blender/python/intern/bpy_rnamakesdna/DNA_defaults.h
@@ -40,6 +40,8 @@ uint8_t *_DNA_struct_default_alloc_impl(const uint8_t *data_src,
size_t size,
const char *alloc_str);
+uint8_t *_DNA_struct_default_alloc_from_nr_impl(const int nr, const char *alloc_str);
+
/**
* Wrap with macro that casts correctly.
*/
@@ -52,6 +54,9 @@ uint8_t *_DNA_struct_default_alloc_impl(const uint8_t *data_src,
sizeof(struct_name), \
__func__)
+#define DNA_struct_default_alloc_from_nr(nr) \
+ (void *)_DNA_struct_default_alloc_from_nr_impl(nr, __func__)
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c
index fd23c5c618f..99cedaa22c4 100644
@@ -1545,32 +1545,19 @@ int pyrna_pydict_to_props(PointerRNA *ptr--- a/source/blender/makesdna/intern/dna_defaults.c
+++ b/source/blender/makesdna/intern/dna_defaults.c
@@ -85,6 +85,8 @@
#include "IMB_imbuf.h"
#include "DNA_defaults.h"
+#include "DNA_genfile.h"
+#include "DNA_sdna_types.h"
#include "DNA_armature_types.h"
#include "DNA_asset_types.h"
@@ -583,3 +585,20 @@ uint8_t *_DNA_struct_default_alloc_impl(const uint8_t *data_src,
return error_val;memcpy(data_dst, data_src, size);
return data_dst;
}
+
+uint8_t *_DNA_struct_default_alloc_from_nr_impl(const int nr, const char *alloc_str)
+{
+ const SDNA *sdna = DNA_sdna_current_get();
+ BLI_assert((nr >= 0) && (nr < sdna->structs_len));
+ const SDNA_Struct *struct_info = sdna->structs[nr];
+ const size_t size = sdna->types_size[struct_info->type];
+ uint8_t *data_dst = MEM_mallocN(size, alloc_str);
+ const uint8_t *data_src = DNA_default_table[nr];
+ if (data_src) {
+ memcpy(data_dst, data_src, size);
+ }
+ else {
+ memset(data_dst, 0x0, size);
+ }
+ return data_dst;
+}
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 47afa0f9a13..12bb125385b 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -830,6 +830,12 @@ void RNA_struct_py_type_set(StructRNA *srna, void *py_type);
void *RNA_struct_blender_type_get(StructRNA *srna);
void RNA_struct_blender_type_set(StructRNA *srna, void *blender_type);
-static PyObject *pyrna_pydict_to_ptr_alloc(+/**
- PointerRNA *ptr, PropertyRNA *prop, PyObject *value, bool *r_is_dna, const char *error_prefix)+ * \return the DNA index compatible with #DNA_struct_find_nr
+static PyObject *pyrna_pydict_to_ptr_alloc(PointerRNA *ptr,+ * or -1 when there is no associated struct.
+ PropertyRNA *prop,+ */
+ PyObject *value,+int RNA_struct_dna_index_get(const StructRNA *srna);
+ const char *error_prefix)
{struct IDProperty **RNA_struct_idprops_p(PointerRNA *ptr);
struct IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create);
bool RNA_struct_idprops_check(StructRNA *srna);
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index e37eb9f7188..d9c2ef9752b 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -374,6 +374,11 @@ typedef enum ParameterFlag {
* \note only for input parameters!
*/
StructRNA *ptr_type = RNA_property_pointer_type(ptr, prop);PARM_PYFUNC_OPTIONAL = (1 << 3),
+ /**
+ * Support coercing dictionary into RNA structs (for Python).
- PointerRNA value_ptr;+ * The struct must either be part of DNA or use ID-properties such as "OperatorProperties".
- void *data;+ */
+ PARM_RNAPTR_COERCE = (1 << 4),
} ParameterFlag;
struct CollectionPropertyIterator;
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 0fadbda5a18..50028aa89e6 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -4271,7 +4271,7 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE
const int nr = RNA_struct_dna_index_get(ptr_type);fprintf(f, "\t");
- if (nr != -1) { rna_print_c_string(f, srna->identifier);
- *r_is_dna = true; fprintf(f, ", NULL, NULL"); /* PyType - Can't initialize here */
- fprintf(f, ", %d, NULL, ", srna->flag);
- data = DNA_struct_default_alloc_from_nr(nr);+ fprintf(f, ", %d, %d, NULL, ", srna->dna_index, srna->flag);
- RNA_pointer_create(NULL, ptr_type, data rna_print_c_string(f, &value_ptr);srna->name);
- } fprintf(f, ",\n\t");
- else { rna_print_c_string(f, srna->description);
- *r_is_dna = false;diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
- IDPropertyTemplate val = {0};index 63eb016b5de..243584915c3 100644
- data = (void *)IDP_New(IDP_GROUP, &val, "");--- a/source/blender/makesrna/intern/rna_access.c
- }+++ b/source/blender/makesrna/intern/rna_access.c
-@@ -914,6 +914,11 @@ void RNA_struct_blender_type_set(StructRNA *srna, void *blender_type)
BLI_assert(nr != -1);srna->blender_type = blender_type;
+ uint8_t *data = DNA_struct_default_alloc_from_nr(nr); }
+ PointerRNA value_ptr;
+int RNA_struct_dna_index_get(const StructRNA *srna)
+ RNA_p+{
+ return srna->dna_index;
+}
+
char *RNA_struct_name_get_alloc(Pointer_create(NULLrRNA *ptr, char *fixedbuf, ptr_typeint fixedlen, data,int *r_len)
&value_ptr);{
if (pyrna_pydict_to_props(&value_ptr, value, false, error_prefix) == -1) {PropertyRNA *nameprop;
- if (nr != -1) {diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
- MEM_freeN(data);index b17ca7d8d59..68a421007f2 100644
- }--- a/source/blender/makesrna/intern/rna_define.c
- else {+++ b/source/blender/makesrna/intern/rna_define.c
- IDP_FreeProperty((IDProperty *)data);@@ -1084,6 +1084,9 @@ void RNA_def_struct_sdna(StructRNA *srna, const char *structname)
- } #endif
+ MEM_freeN(data);
ds->dnaname = structname;
return NULL;+
+ /* May by -1, which is fine. */
+ srna->dna_index = DNA_struct_find_nr_wrapper(DefRNA.sdna, structname);
}
void RNA_def_struct_sdna_from(StructRNA *srna, const char *structname, const char *propname)
@@ -1535,6 +1538,10 @@ void RNA_def_parameter_flags(PropertyRNA *prop,
{
prop->flag |= flag_property;
prop->flag_parameter |= flag_parameter;
+
+ if (flag_parameter & PARM_RNAPTR_COERCE) {
+ BLI_assert(prop->type == PROP_POINTER);
+ }
}
void RNA_def_parameter_clear_flags(PropertyRNA *prop,
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index af13baad5a2..745b12f1e1f 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -709,17 +709,17 @@ static void rna_def_imageuser(BlenderRNA *brna)
prop = RNA_def_property(srna, "multilayer_layer", PROP_INT, PROP_UNSIGNED);
return pyrna_struct_CreatePyObject(&value_ptr);RNA_def_property_int_sdna(prop, NULL, "layer");
@@ -6119,10 +6106,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self- RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */
+ // RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */
RNA_def_property_ui_text(prop, PyObject *args"Layer", PyObject"Layer in multilayer image");
PropertyRNA *pret_single = NULL;prop = RNA_def_property(srna, "multilayer_pass", PROP_INT, PROP_UNSIGNED);
void *retdata_single =RNA_def_property_int_sdna(prop, NULL;, "pass");
- struct {- RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */
- BPy_StructRNA *py_srna;+ // RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */
- bool is_dna; RNA_def_property_ui_text(prop, "Pass", "Pass in multilayer image");
- } * items_alloc;
prop = RNA_def_property(srna, "multilayer_view", PROP_INT, PROP_UNSIGNED);
+ BPy_StructRNA **items_alloc = NULL; RNA_def_property_int_sdna(prop, NULL, "view");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */
+ // RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */
int items_alloc_count = 0;RNA_def_property_ui_text(prop, "View", "View in multilayer image");
/* enable this so all strings are copied and freed after calling.prop = RNA_def_property(srna, "tile", PROP_INT, PROP_UNSIGNED);
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 1c04805be8b..364a50f6b11 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
@@ -6265,22 +6249,19 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -61,8 +61,12 @@ static void rna_ImagePackedFile_save(ImagePackedFile *imapf, Main *bmain, Report
}
}
-static void rna_Image_save_render(
- Image *image, bContext *C, ReportList *reports, const char *path, PyObject *args,Scene *scene)
+static void rna_Image_save_render(Image *image,
+ bContext *C,
+ ReportList *reports,
+ const char *path,
+ Scene *scene,
+ ImageUser *iuser)
PyObject{
ImBuf *ibuf;
@@ -71,12 +75,16 @@ static void rna_Image_save_render(
}
if (scene) {
- ImageUser iuser = {NULL};
+ ImageUser iuser_copy = *iuser;
if ((flag_parameter & PARM_RNAPTR_COERCE) && PyDict_CheckExact(item)) {void *lock;
- const PropertyType typiuser.scene = RNA_property_type(parm);scene;
+ BLI_assert(type == PROP_POINTER);if (iuser_copy.scene == NULL) {
-+ bool is_dna;iuser_copy.scene = scene;
- item = pyrna_pydict_to_ptr_alloc(&funcptr, parm, item, &is_dna, "");+ }
+ item = pyrna_pydict_to_ptr_alloc(&funcpt
+ printf("iuser_copy: %d %d %d\n", iuser_copy.view, iuser_copy.layer, iuser_copy.pass);
- ibuf = BKE_image_acquire_ibuf(image, &iuser, parm&lock);
+ ibuf = BKE_image_acquire_ibuf(image, item&iuser_copy, "");&lock);
if (ibuf == NULL) {
if (item == NULL) {BKE_report(reports, RPT_ERROR, "Could not acquire buffer from image");
PyErr_Clear(); /* Re-raise. */@@ -291,6 +299,8 @@ void RNA_api_image(StructRNA *srna)
pyrna_func_error_prefix(selfparm = RNA_def_string_file_path(func, parm"filepath", kw_arg ?NULL, -1 : i0, error_prefix"", sizeof(error_prefix));"Save path");
- pyrna_pydict_to_ptr_alloc(&funcptr, parm, item RNA_def_parameter_flags(parm, &is_dna0, error_prefix);PARM_REQUIRED);
+ pyrna_pydict_to_ptr_alloc(&funcptr RNA_def_pointer(func, "scene", parm"Scene", item"", error_prefix);"Scene to take image parameters from");
err = -1;+ parm = RNA_def_pointer(func, "image_user", "ImageUser", "", "Image user for saving");
-+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR_COERCE);
func = RNA_def_function(srna, "save", "rna_Image_save");
RNA_def_function_ui_description(func, "Save image to its source path");
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index 723ae384fdf..a744d5b6684 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -513,6 +513,9 @@ struct StructRNA {
void *py_type;
void *blender_type;
+ /** Index in (-1 when not DNA). */
+ int dna_index;
+
/* various options */
int flag;
/* Each StructRNA type can define own tags which properties can set
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 2be2105d327..3c000921667 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -35,6 +35,9 @@ set(INC
../../../../intern/guardedalloc
../../../../intern/mantaflow/extern
../../../../intern/opencolorio
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern
)
set(INC_SYS
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index a79a0ed32bf..efd7a4d8ade 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -31,6 +31,7 @@
#include "RNA_types.h"
+#include "BLI_alloca.h"
#include "BLI_bitmap.h"
#include "BLI_dynstr.h"
#include "BLI_listbase.h"
@@ -56,6 +57,8 @@
#include "RNA_define.h" /* RNA_def_property_free_identifier */
#include "RNA_enum_types.h"
+#include "DNA_defaults.h"
+
#include "CLG_log.h"
#include "MEM_guardedalloc.h"
@@ -1501,6 +1504,14 @@ int pyrna_pydict_to_props(PointerRNA *ptr,
error_val = -1; /* pyrna_py_to_prop sets the error. */
break;
}
+ /* Allocate once (normally `alloca` is avoided in a loop). */if (RNA_property_flag(prop) & PROP_NEVER_NULL) {
+ if (items_alloc == NULL) {PyErr_Format(PyExc_TypeError,
items_alloc = BLI_array_alloca(items_alloc,+ "%.200s: keyword \"%.200s\" isn't set but is marked NEVER NULL",
+ error_prefix,
+ arg_name ? arg_name : "<UNKNOWN>");
+ error_val = -1; /* pyrna_py_to_prop sets the error. parms_len);*/
+ break;
+ }
}
else {
if (pyrna_py_to_prop(ptr, prop, NULL, item, error_prefix)) {
@@ -1534,6 +1545,24 @@ int pyrna_pydict_to_props(PointerRNA *ptr,
return error_val;
}
- items_alloc[items_alloc_count].py_srna = (BPy_Struct
+static PyObject *pyrna_pydict_to_ptr_alloc(PointerRNA *)item;ptr,
-+ items_alloc[items_alloc_count].is_dna = is_dna; PropertyRNA *prop,
+ items_alloc[items_alloc_count++] = (BPy_StructRNA *)item; PyObject *value,
+ const char *error_prefix)
+{
+ StructRNA *ptr_type = RNA_property_pointer_type(ptr, prop);
+ const int nr = RNA_struct_dna_index_get(ptr_type);
+ BLI_assert(nr != -1);
+ uint8_t *data = DNA_struct_default_alloc_from_nr(nr);
+ PointerRNA value_ptr;
+ RNA_pointer_create(NULL, ptr_type, data, &value_ptr);
+ if (pyrna_pydict_to_props(&value_ptr, value, false, error_prefix) == -1) {
+ MEM_freeN(data);
+ return NULL;
+ }
+ return pyrna_struct_CreatePyObject(&value_ptr);
+}
+
static PyObject *pyrna_func_to_py(const PointerRNA *ptr, FunctionRNA *func)
{
BPy_FunctionRNA *pyfunc = (BPy_FunctionRNA *)PyObject_NEW(BPy_FunctionRNA, &pyrna_func_Type);
@@ -6031,6 +6060,36 @@ static PyObject *small_dict_get_item_string(PyObject *dict, const char *key_look
return NULL;
}
err = pyrna_py_to_prop(&funcptr, parm, iter.data, item, "");+/**
+ * \param parm_index: The argument index or -1 for keyword arguments.
+ */
+static void pyrna_func_error_prefix(BPy_FunctionRNA *self,
+ PropertyRNA *parm,
+ const int parm_index,
@@ -6434,20 +6415,12 @@+ char *error,
+ const size_t error_size)
+{
+ PointerRNA *self_ptr = &self->ptr;
+ FunctionRNA *self_func = self->func;
+ if (parm_index == -1) {
+ BLI_snprintf(error,
+ error_size,
+ "%.200s.%.200s(): error with keyword argument \"%.200s\" - ",
+ RNA_struct_identifier(self_ptr->type),
+ RNA_function_identifier(self_func),
+ RNA_property_identifier(parm));
+ }
+ else {
+ BLI_snprintf(error,
+ error_size,
+ "%.200s.%.200s(): error with argument %d, \"%.200s\" - ",
+ RNA_struct_identifier(self_ptr->type),
+ RNA_function_identifier(self_func),
+ parm_index,
+ RNA_property_identifier(parm));
+ }
+}
+
static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject *kw)
PyObject{
RNA_parameter_list_free(&parms)/* NOTE: both BPy_StructRNA and BPy_PropertyRNA can be used here. */
@@ -6047,6 +6106,8 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
PropertyRNA *pret_single = NULL;
void *retdata_single = NULL;
+ BPy_StructRNA **items_alloc = NULL;
+ int items_alloc_count = 0;
/* Cleanup any coerc/* enable this so all strings are copied and freed arguments. */fter calling.
- while (items_alloc_count > 0) { * this exposes bugs where the pointer to the string is held and re-used */
- items_alloc_count--;@@ -6180,32 +6241,34 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
}
- BPy_StructRNA *py_srna = items_alloc[items_alloc_count].py_srna; }
- const bool is_dna = items_alloc[items_alloc_count].is_dna; #endif
- err = pyrna_py_to_prop(&funcptr, parm, iter.data, item, "");
-
+ while (UNLIKELY(--items_alloc_count >= 0)) {- if (err != 0) {
+- item = (PyObject *)items_alloc[items_alloc_count];/* the error generated isn't that useful, so generate it again with a useful prefix
BLI_assert(item->ob_refcnt == 1);- * could also write a function to prepend to error messages */
- char error_prefix[512];
- PyErr_Clear(); /* Re-raise. */
- if (kw_arg == true) {
- if (is_dna) { BLI_snprintf(error_prefix,
- MEM_freeN(py_srna->ptr.data); sizeof(error_prefix),
- } "%.200s.%.200s(): error with keyword argument \"%.200s\" - ",
- else { RNA_struct_identifier(self_ptr->type),
- IDP_FreeProperty(py_srna->ptr.data); RNA_function_identifier(self_func),
- } RNA_property_identifier(parm));
- py_srna->ptr.data = NULL;+ /* The error generated isn't that useful, so generate it again with a useful prefix
- Py_DECREF((PyObject *)py_srna);+ * could also write a function to prepend to error messages. */
+ char error_prefix[512];
+
+ if ((flag_parameter & PARM_RNAPTR_COERCE) && PyDict_CheckExact(item)) {
+ const PropertyType type = RNA_property_type(parm);
+ BLI_assert(type == PROP_POINTER);
+ item = pyrna_pydict_to_ptr_alloc(&funcptr, parm, item, "");
+ if (item == NULL) {
+ PyErr_Clear(); /* Re-raise. */
+ pyrna_func_error_prefix(self, parm, kw_arg ? -1 : i, error_prefix, sizeof(error_prefix));
+ pyrna_pydict_to_ptr_alloc(&funcptr, parm, item, error_prefix);
+ err = -1;
+ break;
}
- else {
- BLI_snprintf(error_prefix,
- sizeof(error_prefix),
- "%.200s.%.200s(): error with argument %d, \"%.200s\" - ",
- RNA_struct_identifier(self_ptr->type),
- RNA_function_identifier(self_func),
- i,
- RNA_property_identifier(parm));
+ /* Allocate once (normally `alloca` is avoided in a loop). */
+ if (items_alloc == NULL) {
+ items_alloc = BLI_array_alloca(items_alloc, parms_len);
}
+ items_alloc[items_alloc_count++] = (BPy_StructRNA *)item;
+ }
+ err = pyrna_py_to_prop(&funcptr, parm, iter.data, item, "");
+
+ if (err != 0) {
+ PyErr_Clear(); /* Re-raise. */
+ pyrna_func_error_prefix(self, parm, kw_arg ? -1 : i, error_prefix, sizeof(error_prefix));
pyrna_py_to_prop(&funcptr, parm, iter.data, item, error_prefix);
break;
@@ -6351,6 +6414,15 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
RNA_parameter_list_end(&iter);
RNA_parameter_list_free(&parms);
+ /* Cleanup any coerced arguments. */
+ while (UNLIKELY(--items_alloc_count >= 0)) {
+ item = (PyObject *)items_alloc[items_alloc_count];
+ BLI_assert(item->ob_refcnt == 1);
+ MEM_freeN(((BPy_StructRNA *)item)->ptr.data);
+ ((BPy_StructRNA *)item)->ptr.data = NULL;
+ Py_DECREF((PyObject *)item);
}+ }
+
if (ret) {
return ret;
}