Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2017-11-29 17:31:31 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2017-11-29 19:23:25 +0300
commit638afb9bd428fb697fb5136e8bb5f31b05458db7 (patch)
tree2c00bf3c3d394e37db9286306ba4e6506e31a31e /source
parent6d003ef81272be144e97e2767ee4fe526aca582c (diff)
ID Static Override, part II: RNA changes.
This is essentially a huge refactor/extension of our existing RNA compare & copy code, since static override needs more advanced handling here. Note that not all new features are implemented yet, advanced things like collections insertion/deletion are still TODO (medium priority). This completes the ground work for overrides, remaining commits will be about UI and some basic/testing activation of overrides for a limited set of data-blocks & properties. For details see https://developer.blender.org/D2417
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/intern/library_override.c28
-rw-r--r--source/blender/makesrna/RNA_access.h57
-rw-r--r--source/blender/makesrna/RNA_define.h2
-rw-r--r--source/blender/makesrna/RNA_types.h5
-rw-r--r--source/blender/makesrna/intern/makesrna.c7
-rw-r--r--source/blender/makesrna/intern/rna_ID.c30
-rw-r--r--source/blender/makesrna/intern/rna_access.c694
-rw-r--r--source/blender/makesrna/intern/rna_define.c31
-rw-r--r--source/blender/makesrna/intern/rna_internal.h36
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h62
-rw-r--r--source/blender/makesrna/intern/rna_rna.c1009
11 files changed, 1712 insertions, 249 deletions
diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c
index bc69b085e57..22896cff64a 100644
--- a/source/blender/blenkernel/intern/library_override.c
+++ b/source/blender/blenkernel/intern/library_override.c
@@ -384,10 +384,10 @@ bool BKE_override_static_status_check_local(ID *local)
RNA_id_pointer_create(local, &rnaptr_local);
RNA_id_pointer_create(reference, &rnaptr_reference);
-// if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, true, true)) {
-// local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
-// return false;
-// }
+ if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, true, true)) {
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
+ return false;
+ }
return true;
}
@@ -428,10 +428,10 @@ bool BKE_override_static_status_check_reference(ID *local)
RNA_id_pointer_create(local, &rnaptr_local);
RNA_id_pointer_create(reference, &rnaptr_reference);
-// if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, false, true)) {
-// local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
-// return false;
-// }
+ if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, false, true)) {
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
+ return false;
+ }
return true;
}
@@ -459,7 +459,7 @@ bool BKE_override_static_operations_create(ID *local)
RNA_id_pointer_create(local, &rnaptr_local);
RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
-// ret = RNA_struct_auto_override(&rnaptr_local, &rnaptr_reference, local->override_static, NULL);
+ ret = RNA_struct_auto_override(&rnaptr_local, &rnaptr_reference, local->override_static, NULL);
#ifndef NDEBUG
if (ret) {
printf("We did generate static override rules for %s\n", local->name);
@@ -534,7 +534,7 @@ void BKE_override_static_update(Main *bmain, ID *local)
RNA_id_pointer_create(local->override_static->storage, rnaptr_storage);
}
-// RNA_struct_override_apply(&rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_static);
+ RNA_struct_override_apply(&rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_static);
/* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa. So when we'll free tmp_id,
* we'll actually free old, outdated data from local. */
@@ -634,10 +634,10 @@ ID *BKE_override_static_operations_store_start(OverrideStaticStorage *override_s
RNA_id_pointer_create(local, &rnaptr_final);
RNA_id_pointer_create(storage_id, &rnaptr_storage);
-// if (!RNA_struct_override_store(&rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_static)) {
-// BKE_libblock_free_ex(override_storage, storage_id, true, false);
-// storage_id = NULL;
-// }
+ if (!RNA_struct_override_store(&rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_static)) {
+ BKE_libblock_free_ex(override_storage, storage_id, true, false);
+ storage_id = NULL;
+ }
}
local->override_static->storage = storage_id;
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 60c2480a2ff..cab6e938048 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -39,6 +39,9 @@ extern "C" {
struct bContext;
struct ID;
+struct IDOverrideStatic;
+struct IDOverrideStaticProperty;
+struct IDOverrideStaticPropertyOperation;
struct ListBase;
struct Main;
struct ReportList;
@@ -1042,7 +1045,7 @@ char *RNA_path_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int
* call RNA_struct_find_property. The names have to exist as RNA properties
* for the type in the pointer, if they do not exist an error will be printed.
*
- * There is no support for pointers and collections here yet, these can be
+ * There is no support for pointers and collections here yet, these can be
* added when ID properties support them. */
int RNA_boolean_get(PointerRNA *ptr, const char *name);
@@ -1234,17 +1237,51 @@ StructRNA *ID_code_to_RNA_type(short idcode);
void _RNA_warning(const char *format, ...) ATTR_PRINTF_FORMAT(1, 2);
-/* Equals test (skips pointers and collections)
- * is_strict false assumes uninitialized properties are equal */
+/* Equals test. */
-typedef enum eRNAEqualsMode {
- RNA_EQ_STRICT, /* set/unset ignored */
- RNA_EQ_UNSET_MATCH_ANY, /* unset property matches anything */
- RNA_EQ_UNSET_MATCH_NONE /* unset property never matches set property */
-} eRNAEqualsMode;
+/* Note: In practice, EQ_STRICT and EQ_COMPARE have same behavior currently, and will yield same result. */
+typedef enum eRNACompareMode {
+ /* Only care about equality, not full comparison. */
+ RNA_EQ_STRICT, /* set/unset ignored */
+ RNA_EQ_UNSET_MATCH_ANY, /* unset property matches anything */
+ RNA_EQ_UNSET_MATCH_NONE, /* unset property never matches set property */
+ /* Full comparison. */
+ RNA_EQ_COMPARE,
+} eRNACompareMode;
-bool RNA_property_equals(struct PointerRNA *a, struct PointerRNA *b, struct PropertyRNA *prop, eRNAEqualsMode mode);
-bool RNA_struct_equals(struct PointerRNA *a, struct PointerRNA *b, eRNAEqualsMode mode);
+bool RNA_property_equals(struct PointerRNA *a, struct PointerRNA *b, struct PropertyRNA *prop, eRNACompareMode mode);
+bool RNA_struct_equals(struct PointerRNA *a, struct PointerRNA *b, eRNACompareMode mode);
+
+/* Override. */
+
+bool RNA_struct_override_matches(struct PointerRNA *local, struct PointerRNA *reference,
+ struct IDOverrideStatic *override, const bool ignore_non_overridable, const bool ignore_overridden);
+
+bool RNA_struct_override_store(
+ struct PointerRNA *local, struct PointerRNA *reference, PointerRNA *storage, struct IDOverrideStatic *override);
+
+void RNA_property_override_apply(
+ struct PointerRNA *dst, struct PointerRNA *src, struct PointerRNA *storage, struct PropertyRNA *prop,
+ struct IDOverrideStaticProperty *op);
+void RNA_struct_override_apply(
+ struct PointerRNA *dst, struct PointerRNA *src, struct PointerRNA *storage,
+ struct IDOverrideStatic *override);
+
+bool RNA_struct_auto_override(
+ struct PointerRNA *local, struct PointerRNA *reference, struct IDOverrideStatic *override, const char *root_path);
+
+struct IDOverrideStaticProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop);
+struct IDOverrideStaticProperty *RNA_property_override_property_get(PointerRNA *ptr, PropertyRNA *prop, bool *r_created);
+
+struct IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_find(
+ PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict);
+struct IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_get(
+ PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index,
+ const bool strict, bool *r_strict, bool *r_created);
+
+void RNA_property_override_status(
+ PointerRNA *ptr, PropertyRNA *prop, const int index,
+ bool *r_overridable, bool *r_overridden, bool *r_mandatory, bool *r_locked);
#ifdef __cplusplus
}
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index e9e4276b235..4e32651d356 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -177,6 +177,8 @@ void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *update
void RNA_def_property_editable_func(PropertyRNA *prop, const char *editable);
void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editable);
+void RNA_def_property_override_funcs(PropertyRNA *prop, const char *diff, const char *store, const char *apply);
+
void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func);
void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func);
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 4a8df4d6a7f..a3bba1984c1 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -158,7 +158,7 @@ typedef enum PropertySubType {
/* Make sure enums are updated with these */
/* HIGHEST FLAG IN USE: 1 << 31
- * FREE FLAGS: 2, 3, 7, 9, 11, 13, 14, 15, 30 */
+ * FREE FLAGS: 3, 7, 9, 11, 13, 14, 15, 30 */
typedef enum PropertyFlag {
/* editable means the property is editable in the user
* interface, properties are editable by default except
@@ -176,6 +176,9 @@ typedef enum PropertyFlag {
* and collections */
PROP_ANIMATABLE = (1 << 1),
+ /* Means the property can be overriden by a local 'proxy' of some linked datablock. */
+ PROP_OVERRIDABLE = (1 << 2),
+
/* This flag means when the property's widget is in 'textedit' mode, it will be updated
* after every typed char, instead of waiting final validation. Used e.g. for text searchbox.
* It will also cause UI_BUT_VALUE_CLEAR to be set for text buttons. We could add an own flag
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index b927daf2ac0..19f66109665 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -3025,12 +3025,15 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
prop->arraylength[1],
prop->arraylength[2],
prop->totarraylength);
- fprintf(f, "\t%s%s, %d, %s, %s,\n",
+ fprintf(f, "\t%s%s, %d, %s, %s, %s, %s, %s,\n",
(prop->flag & PROP_CONTEXT_UPDATE) ? "(UpdateFunc)" : "",
rna_function_string(prop->update),
prop->noteflag,
rna_function_string(prop->editable),
- rna_function_string(prop->itemeditable));
+ rna_function_string(prop->itemeditable),
+ rna_function_string(prop->override_diff),
+ rna_function_string(prop->override_store),
+ rna_function_string(prop->override_apply));
if (prop->flag_internal & PROP_INTERN_RAW_ACCESS) rna_set_raw_offset(f, srna, prop);
else fprintf(f, "\t0, -1");
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index c519c61e9e9..44df8916796 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -97,6 +97,7 @@ const EnumPropertyItem rna_enum_id_type_items[] = {
#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_library_override.h"
#include "BKE_library_remap.h"
#include "BKE_animsys.h"
#include "BKE_material.h"
@@ -311,6 +312,15 @@ static ID *rna_ID_copy(ID *id, Main *bmain)
return NULL;
}
+static ID *rna_ID_override_create(ID *id, Main *bmain)
+{
+ if (id->lib == NULL) {
+ return NULL;
+ }
+
+ return BKE_override_static_create_from(bmain, id);
+}
+
static void rna_ID_update_tag(ID *id, ReportList *reports, int flag)
{
/* XXX, new function for this! */
@@ -762,6 +772,14 @@ static PointerRNA rna_IDPreview_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_ImagePreview, prv_img);
}
+static PointerRNA rna_ID_override_reference_get(PointerRNA *ptr)
+{
+ ID *id = (ID *)ptr->data;
+ ID *reference = (id && id->override_static) ? id->override_static->reference : NULL;
+
+ return reference ? rna_pointer_inherit_refine(ptr, ID_code_to_RNA_type(GS(reference->name)), reference) : PointerRNA_NULL;
+}
+
#else
static void rna_def_ID_properties(BlenderRNA *brna)
@@ -1024,6 +1042,12 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Library", "Library file the data-block is linked from");
+ prop = RNA_def_pointer(srna, "override_static_reference", "ID",
+ "Override Reference", "Reference linked data-block overridden by this one");
+ RNA_def_property_pointer_sdna(prop, NULL, "override_static->reference");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, "rna_ID_override_reference_get", NULL, NULL, NULL);
+
prop = RNA_def_pointer(srna, "preview", "ImagePreview", "Preview",
"Preview image and icon of this data-block (None if not supported for this type of data)");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1036,6 +1060,12 @@ static void rna_def_ID(BlenderRNA *brna)
parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "override_create", "rna_ID_override_create");
+ RNA_def_function_ui_description(func, "Create an overridden local copy of this linked data-block (not supported for all data-blocks)");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
+ parm = RNA_def_pointer(func, "id", "ID", "", "New overridden local copy of the ID");
+ RNA_def_function_return(func, parm);
+
func = RNA_def_function(srna, "user_clear", "rna_ID_user_clear");
RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, "
"on reload the data will be removed");
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 49b50858f93..a1f059a9487 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -51,6 +51,7 @@
#include "BKE_idprop.h"
#include "BKE_fcurve.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -1817,7 +1818,8 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop)
return ((flag & PROP_EDITABLE) &&
(flag & PROP_REGISTER) == 0 &&
- (!id || !ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)));
+ (!id || ((!ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)) &&
+ (!id->override_static || (prop->flag & PROP_OVERRIDABLE)))));
}
/**
@@ -1843,11 +1845,19 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char *
}
/* property from linked data-block */
- if (id && ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
- if (!(*r_info)[0]) {
- *r_info = "Can't edit this property from a linked data-block.";
+ if (id) {
+ if (ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
+ if (!(*r_info)[0]) {
+ *r_info = "Can't edit this property from a linked data-block.";
+ }
+ return false;
+ }
+ if (id->override_static != NULL && (prop->flag & PROP_OVERRIDABLE) == 0) {
+ if (!(*r_info)[0]) {
+ *r_info = "Can't edit this property from an override data-block.";
+ }
+ return false;
}
- return false;
}
return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0);
@@ -6959,120 +6969,22 @@ bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index)
}
}
+static bool rna_property_override_operation_apply(
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local,
+ IDOverrideStaticPropertyOperation *opop);
+
bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index)
{
- int len, fromlen;
- PropertyRNA *fromprop = prop;
-
- if (prop->magic != RNA_MAGIC) {
- /* In case of IDProperty, we have to find the *real* idprop of ptr,
- * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
- prop = (PropertyRNA *)rna_idproperty_find(ptr, ((IDProperty *)fromprop)->name);
-
- /* its possible the custom-prop doesn't exist on this data-block */
- if (prop == NULL) {
- return false;
- }
-
- /* Even though currently we now prop will always be the 'fromprop', this might not be the case in the future. */
- if (prop == fromprop) {
- fromprop = (PropertyRNA *)rna_idproperty_find(fromptr, ((IDProperty *)prop)->name);
- }
- }
-
- /* get the length of the array to work with */
- len = RNA_property_array_length(ptr, prop);
- fromlen = RNA_property_array_length(fromptr, fromprop);
-
- if (len != fromlen)
+ if (!RNA_property_editable(ptr, prop)) {
return false;
-
- /* get and set the default values as appropriate for the various types */
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- if (len) {
- if (index == -1) {
- int *tmparray = MEM_callocN(sizeof(int) * len, "copy - boolean");
-
- RNA_property_boolean_get_array(fromptr, fromprop, tmparray);
- RNA_property_boolean_set_array(ptr, prop, tmparray);
-
- MEM_freeN(tmparray);
- }
- else {
- int value = RNA_property_boolean_get_index(fromptr, fromprop, index);
- RNA_property_boolean_set_index(ptr, prop, index, value);
- }
- }
- else {
- int value = RNA_property_boolean_get(fromptr, fromprop);
- RNA_property_boolean_set(ptr, prop, value);
- }
- return true;
- case PROP_INT:
- if (len) {
- if (index == -1) {
- int *tmparray = MEM_callocN(sizeof(int) * len, "copy - int");
-
- RNA_property_int_get_array(fromptr, fromprop, tmparray);
- RNA_property_int_set_array(ptr, prop, tmparray);
-
- MEM_freeN(tmparray);
- }
- else {
- int value = RNA_property_int_get_index(fromptr, fromprop, index);
- RNA_property_int_set_index(ptr, prop, index, value);
- }
- }
- else {
- int value = RNA_property_int_get(fromptr, fromprop);
- RNA_property_int_set(ptr, prop, value);
- }
- return true;
- case PROP_FLOAT:
- if (len) {
- if (index == -1) {
- float *tmparray = MEM_callocN(sizeof(float) * len, "copy - float");
-
- RNA_property_float_get_array(fromptr, fromprop, tmparray);
- RNA_property_float_set_array(ptr, prop, tmparray);
-
- MEM_freeN(tmparray);
- }
- else {
- float value = RNA_property_float_get_index(fromptr, fromprop, index);
- RNA_property_float_set_index(ptr, prop, index, value);
- }
- }
- else {
- float value = RNA_property_float_get(fromptr, fromprop);
- RNA_property_float_set(ptr, prop, value);
- }
- return true;
- case PROP_ENUM:
- {
- int value = RNA_property_enum_get(fromptr, fromprop);
- RNA_property_enum_set(ptr, prop, value);
- return true;
- }
- case PROP_POINTER:
- {
- PointerRNA value = RNA_property_pointer_get(fromptr, fromprop);
- RNA_property_pointer_set(ptr, prop, value);
- return true;
- }
- case PROP_STRING:
- {
- char *value = RNA_property_string_get_alloc(fromptr, fromprop, NULL, 0, NULL);
- RNA_property_string_set(ptr, prop, value);
- MEM_freeN(value);
- return true;
- }
- default:
- return false;
}
- return false;
+ IDOverrideStaticPropertyOperation opop = {
+ .operation = IDOVERRIDESTATIC_OP_REPLACE,
+ .subitem_reference_index = index,
+ .subitem_local_index = index
+ };
+ return rna_property_override_operation_apply(ptr, fromptr, NULL, prop, &opop);
}
/* use RNA_warning macro which includes __func__ suffix */
@@ -7097,176 +7009,514 @@ void _RNA_warning(const char *format, ...)
#endif
}
-bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNAEqualsMode mode)
+static int rna_property_override_diff(
+ PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNACompareMode mode,
+ IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags);
+
+bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNACompareMode mode)
+{
+ BLI_assert(ELEM(mode, RNA_EQ_STRICT, RNA_EQ_UNSET_MATCH_ANY, RNA_EQ_UNSET_MATCH_NONE));
+
+ return (rna_property_override_diff(a, b, prop, mode, NULL, NULL, NULL, 0) != 0);
+}
+
+bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNACompareMode mode)
+{
+ CollectionPropertyIterator iter;
+ PropertyRNA *iterprop;
+ bool equals = true;
+
+ if (a == NULL && b == NULL)
+ return true;
+ else if (a == NULL || b == NULL)
+ return false;
+ else if (a->type != b->type)
+ return false;
+
+ iterprop = RNA_struct_iterator_property(a->type);
+
+ RNA_property_collection_begin(a, iterprop, &iter);
+ for (; iter.valid; RNA_property_collection_next(&iter)) {
+ PropertyRNA *prop = iter.ptr.data;
+
+ if (!RNA_property_equals(a, b, prop, mode)) {
+ equals = false;
+ break;
+ }
+ }
+ RNA_property_collection_end(&iter);
+
+ return equals;
+}
+
+/* Low-level functions, also used by non-override RNA API like copy or equality check. */
+#include "PIL_time_utildefines.h"
+static int rna_property_override_diff(
+ PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop_a, eRNACompareMode mode,
+ IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags)
{
- int len, fromlen;
+ int len_a, len_b;
+
+ PropertyRNA *prop_b = prop_a;
+
+ if (prop_a->magic != RNA_MAGIC) {
+ /* In case of IDProperty, we have to find the *real* idprop of ptr,
+ * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
+ /* XXX TODO this is ugly, we already get correct prop in upcalling code, whould just pass them to this func! */
+ prop_a = (PropertyRNA *)rna_idproperty_find(ptr_a, ((IDProperty *)prop_a)->name);
+ prop_b = (PropertyRNA *)rna_idproperty_find(ptr_b, ((IDProperty *)prop_b)->name);
+
+ if (ELEM(NULL, prop_a, prop_b)) {
+ return 1;
+ }
+ }
+
+ BLI_assert(prop_a->override_diff == prop_b->override_diff && prop_a->override_diff != NULL);
if (mode == RNA_EQ_UNSET_MATCH_ANY) {
/* uninitialized properties are assumed to match anything */
- if (!RNA_property_is_set(a, prop) || !RNA_property_is_set(b, prop))
- return true;
+ if (!RNA_property_is_set(ptr_a, prop_a) || !RNA_property_is_set(ptr_b, prop_b))
+ return 0;
}
else if (mode == RNA_EQ_UNSET_MATCH_NONE) {
/* unset properties never match set properties */
- if (RNA_property_is_set(a, prop) != RNA_property_is_set(b, prop))
- return false;
+ if (RNA_property_is_set(ptr_a, prop_a) != RNA_property_is_set(ptr_b, prop_b))
+ return 1;
}
/* get the length of the array to work with */
- len = RNA_property_array_length(a, prop);
- fromlen = RNA_property_array_length(b, prop);
+ len_a = RNA_property_array_length(ptr_a, prop_a);
+ len_b = RNA_property_array_length(ptr_b, prop_b);
- if (len != fromlen)
- return false;
+ if (len_a != len_b) {
+ /* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */
+ return len_a > len_b ? 1 : -1;
+ }
- /* get and set the default values as appropriate for the various types */
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- {
- if (len) {
- int fixed_a[16], fixed_b[16];
- int *array_a, *array_b;
- bool equals;
+ return prop_a->override_diff(
+ ptr_a, ptr_b, prop_a, prop_b, len_a, len_b, mode, override, rna_path, flags, r_override_changed);
+}
+
+/* Modify local data-block to make it ready for override application (only needed for diff operations, where we use
+ * the local data-block's data as second operand). */
+static bool rna_property_override_operation_store(
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local,
+ IDOverrideStaticProperty *op)
+{
+ int len_local, len_reference, len_storage = 0;
+ PropertyRNA *prop_reference = prop_local;
+ PropertyRNA *prop_storage = prop_local;
+ bool changed = false;
- array_a = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_a;
- array_b = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_b;
+ if (!ptr_storage) {
+ return changed;
+ }
- RNA_property_boolean_get_array(a, prop, array_a);
- RNA_property_boolean_get_array(b, prop, array_b);
+ if (prop_local->magic != RNA_MAGIC) {
+ /* In case of IDProperty, we have to find the *real* idprop of ptr,
+ * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
+ /* XXX TODO this is ugly, we already get correct prop in upcalling code, should just pass them to this func! */
+ prop_local = (PropertyRNA *)rna_idproperty_find(ptr_local, ((IDProperty *)prop_local)->name);
+ prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, ((IDProperty *)prop_reference)->name);
+ if (ptr_storage) {
+ prop_storage = (PropertyRNA *)rna_idproperty_find(ptr_storage, ((IDProperty *)prop_storage)->name);
+ }
- equals = memcmp(array_a, array_b, sizeof(int) * len) == 0;
+ /* its possible the custom-prop doesn't exist on this data-block */
+ if (prop_local == NULL) {
+ return changed;
+ }
+ }
- if (array_a != fixed_a) MEM_freeN(array_a);
- if (array_b != fixed_b) MEM_freeN(array_b);
+ /* get the length of the array to work with */
+ len_local = RNA_property_array_length(ptr_local, prop_local);
+ len_reference = RNA_property_array_length(ptr_reference, prop_reference);
+ if (prop_storage) {
+ len_storage = RNA_property_array_length(ptr_storage, prop_storage);
+ }
- return equals;
- }
- else {
- int value = RNA_property_boolean_get(a, prop);
- return value == RNA_property_boolean_get(b, prop);
- }
+ if (len_local != len_reference || len_local != len_storage) {
+ /* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */
+ return changed;
+ }
+
+ BLI_assert(prop_local->override_store == prop_reference->override_store &&
+ (!ptr_storage || prop_local->override_store == prop_storage->override_store) &&
+ prop_local->override_store != NULL);
+
+ for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ /* Only needed for diff operations. */
+ if (!ELEM(opop->operation, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY)) {
+ continue;
}
- case PROP_INT:
+ if (prop_local->override_store(
+ ptr_local, ptr_reference, ptr_storage, prop_local, prop_reference, prop_storage,
+ len_local, len_reference, len_storage, opop))
{
- if (len) {
- int fixed_a[16], fixed_b[16];
- int *array_a, *array_b;
- bool equals;
+ changed = true;
+ }
+ }
- array_a = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_a;
- array_b = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_b;
+ return changed;
+}
- RNA_property_int_get_array(a, prop, array_a);
- RNA_property_int_get_array(b, prop, array_b);
+static bool rna_property_override_operation_apply(
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local,
+ IDOverrideStaticPropertyOperation *opop)
+{
+ int len_local, len_reference, len_storage = 0;
+ PropertyRNA *prop_reference = prop_local;
+ PropertyRNA *prop_storage = prop_local;
- equals = memcmp(array_a, array_b, sizeof(int) * len) == 0;
+ const short override_op = opop->operation;
- if (array_a != fixed_a) MEM_freeN(array_a);
- if (array_b != fixed_b) MEM_freeN(array_b);
+ if (override_op == IDOVERRIDESTATIC_OP_NOOP) {
+ return true;
+ }
- return equals;
- }
- else {
- int value = RNA_property_int_get(a, prop);
- return value == RNA_property_int_get(b, prop);
- }
+ if (ELEM(override_op, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY) && !ptr_storage) {
+ /* We cannot apply 'diff' override operations without some refference storage.
+ * This should typically only happen at read time of .blend file... */
+ return false;
+ }
+
+ if (prop_local->magic != RNA_MAGIC) {
+ /* In case of IDProperty, we have to find the *real* idprop of ptr,
+ * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
+ /* XXX TODO this is ugly, we already get correct prop in upcalling code, whould just pass them to this func! */
+ prop_local = (PropertyRNA *)rna_idproperty_find(ptr_local, ((IDProperty *)prop_local)->name);
+ prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, ((IDProperty *)prop_reference)->name);
+ if (ptr_storage) {
+ prop_storage = (PropertyRNA *)rna_idproperty_find(ptr_storage, ((IDProperty *)prop_storage)->name);
}
- case PROP_FLOAT:
- {
- if (len) {
- float fixed_a[16], fixed_b[16];
- float *array_a, *array_b;
- bool equals;
+ /* its possible the custom-prop doesn't exist on this data-block */
+ if (prop_local == NULL) {
+ return false;
+ }
+ }
+
+ if (ELEM(override_op, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY) && !prop_storage) {
+ /* We cannot apply 'diff' override operations without some refference storage.
+ * This should typically only happen at read time of .blend file... */
+ return false;
+ }
- array_a = (len > 16) ? MEM_mallocN(sizeof(float) * len, "RNA equals") : fixed_a;
- array_b = (len > 16) ? MEM_mallocN(sizeof(float) * len, "RNA equals") : fixed_b;
+ /* get the length of the array to work with */
+ len_local = RNA_property_array_length(ptr_local, prop_local);
+ len_reference = RNA_property_array_length(ptr_reference, prop_reference);
+ if (ptr_storage) {
+ len_storage = RNA_property_array_length(ptr_storage, prop_storage);
+ }
- RNA_property_float_get_array(a, prop, array_a);
- RNA_property_float_get_array(b, prop, array_b);
+ if (len_local != len_reference || (ptr_storage && len_local != len_storage)) {
+ /* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */
+ return false;
+ }
- equals = memcmp(array_a, array_b, sizeof(float) * len) == 0;
+ BLI_assert(prop_local->override_apply == prop_reference->override_apply &&
+ (!ptr_storage || prop_local->override_apply == prop_storage->override_apply) &&
+ prop_local->override_apply != NULL);
- if (array_a != fixed_a) MEM_freeN(array_a);
- if (array_b != fixed_b) MEM_freeN(array_b);
+ /* get and set the default values as appropriate for the various types */
+ return prop_local->override_apply(
+ ptr_local, ptr_reference, ptr_storage,
+ prop_local, prop_reference, prop_storage,
+ len_local, len_reference, len_storage,
+ opop);
+}
- return equals;
- }
- else {
- float value = RNA_property_float_get(a, prop);
- return value == RNA_property_float_get(b, prop);
+
+/**
+ * Check whether reference and local overriden data match (are the same),
+ * with respect to given restrictive sets of properties. */
+bool RNA_struct_override_matches(
+ PointerRNA *local, PointerRNA *reference,
+ IDOverrideStatic *override, const bool ignore_non_overridable, const bool ignore_overridden)
+{
+ CollectionPropertyIterator iter;
+ PropertyRNA *iterprop;
+ bool equals = true;
+
+ BLI_assert(local->type == reference->type);
+
+ iterprop = RNA_struct_iterator_property(local->type);
+
+ RNA_property_collection_begin(local, iterprop, &iter);
+ for (; iter.valid; RNA_property_collection_next(&iter)) {
+ PropertyRNA *prop = iter.ptr.data;
+
+ if (ignore_non_overridable && !(prop->flag & PROP_OVERRIDABLE)) {
+ continue;
+ }
+
+ if (ignore_overridden) {
+ /* XXX TODO this will have to be refined to handle collections insertions, and array items */
+ char *rna_path = RNA_path_from_ID_to_property(local, prop);
+ if (BKE_override_static_property_find(override, rna_path) != NULL) {
+ MEM_SAFE_FREE(rna_path);
+ continue;
}
+ MEM_SAFE_FREE(rna_path);
}
- case PROP_ENUM:
- {
- int value = RNA_property_enum_get(a, prop);
- return value == RNA_property_enum_get(b, prop);
+ int flag = 0;
+ if (ignore_non_overridable) {
+ flag |= RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE;
+ }
+ if (ignore_overridden) {
+ flag |= RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN;
}
+ if (rna_property_override_diff(local, reference, prop, RNA_EQ_STRICT, override, NULL, NULL, flag) != 0) {
+ equals = false;
+ break;
+ }
+ }
+ RNA_property_collection_end(&iter);
- case PROP_STRING:
- {
- char fixed_a[128], fixed_b[128];
- int len_a, len_b;
- char *value_a = RNA_property_string_get_alloc(a, prop, fixed_a, sizeof(fixed_a), &len_a);
- char *value_b = RNA_property_string_get_alloc(b, prop, fixed_b, sizeof(fixed_b), &len_b);
- bool equals = STREQ(value_a, value_b);
+ return equals;
+}
- if (value_a != fixed_a) MEM_freeN(value_a);
- if (value_b != fixed_b) MEM_freeN(value_b);
+/** Store needed second operands into \a storage data-block for differential override operations. */
+bool RNA_struct_override_store(PointerRNA *local, PointerRNA *reference, PointerRNA *storage, IDOverrideStatic *override)
+{
+ bool changed = false;
- return equals;
- }
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_START_AVERAGED(RNA_struct_override_store);
+#endif
+ for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
+ /* Simplified for now! */
+ PointerRNA src_data, dst_data;
+ PropertyRNA *src_prop, *dst_prop;
- case PROP_POINTER:
+ if (RNA_path_resolve_property(reference, op->rna_path, &src_data, &src_prop) &&
+ RNA_path_resolve_property(local, op->rna_path, &dst_data, &dst_prop))
{
- if (!STREQ(RNA_property_identifier(prop), "rna_type")) {
- PointerRNA propptr_a = RNA_property_pointer_get(a, prop);
- PointerRNA propptr_b = RNA_property_pointer_get(b, prop);
- return RNA_struct_equals(&propptr_a, &propptr_b, mode);
+ PointerRNA storage_data;
+ PropertyRNA *storage_prop = NULL;
+
+ /* It is totally OK if this does not success, only a subset of override operations actually need storage. */
+ if (storage && (storage->id.data != NULL)) {
+ RNA_path_resolve_property(storage, op->rna_path, &storage_data, &storage_prop);
+ }
+
+ if (rna_property_override_operation_store(&dst_data, &src_data, &storage_data, src_prop, op)) {
+ changed = true;
}
- break;
}
+ }
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_END_AVERAGED(RNA_struct_override_store);
+#endif
- default:
- break;
+ return changed;
+}
+
+/** Apply given \a op override property operations on \a dst, using \a src as source. */
+void RNA_property_override_apply(
+ PointerRNA *dst, PointerRNA *src, PointerRNA *storage, PropertyRNA *prop, IDOverrideStaticProperty *op)
+{
+ for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ if (!rna_property_override_operation_apply(dst, src, storage, prop, opop))
+ {
+ BLI_assert(0);
+ }
}
+}
- return true;
+/** Apply given \a override operations on \a dst, using \a src as source. */
+void RNA_struct_override_apply(PointerRNA *dst, PointerRNA *src, PointerRNA *storage, IDOverrideStatic *override)
+{
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_START_AVERAGED(RNA_struct_override_apply);
+#endif
+ for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
+ /* Simplified for now! */
+ PointerRNA src_data, dst_data;
+ PropertyRNA *src_prop, *dst_prop;
+
+ if (RNA_path_resolve_property(src, op->rna_path, &src_data, &src_prop) &&
+ RNA_path_resolve_property(dst, op->rna_path, &dst_data, &dst_prop))
+ {
+ PointerRNA storage_data;
+ PropertyRNA *storage_prop = NULL;
+
+ /* It is totally OK if this does not success, only a subset of override operations actually need storage. */
+ if (storage && (storage->id.data != NULL)) {
+ RNA_path_resolve_property(storage, op->rna_path, &storage_data, &storage_prop);
+ }
+
+ /* Note that src and dst props are the same, unless they are IDProperties... */
+ RNA_property_override_apply(&dst_data, &src_data, storage_prop ? &storage_data : NULL, src_prop, op);
+ }
+#ifndef NDEBUG
+ else {
+ printf("Failed to apply static override operation to '%s.%s' (could not resolve some properties)\n",
+ ((ID *)src->id.data)->name, op->rna_path);
+ }
+#endif
+ }
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_END_AVERAGED(RNA_struct_override_apply);
+#endif
}
-bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNAEqualsMode mode)
+/** Automatically define override rules by comparing \a local and \a reference RNA structs. */
+bool RNA_struct_auto_override(PointerRNA *local, PointerRNA *reference, IDOverrideStatic *override, const char *root_path)
{
CollectionPropertyIterator iter;
-// CollectionPropertyRNA *citerprop; /* UNUSED */
PropertyRNA *iterprop;
- bool equals = true;
+ bool changed = false;
- if (a == NULL && b == NULL)
- return true;
- else if (a == NULL || b == NULL)
- return false;
- else if (a->type != b->type)
- return false;
+ BLI_assert(local->type == reference->type);
+ BLI_assert(local->id.data && reference->id.data);
- iterprop = RNA_struct_iterator_property(a->type);
-// citerprop = (CollectionPropertyRNA *)rna_ensure_property(iterprop); /* UNUSED */
+ if ((((ID *)local->id.data)->flag & LIB_OVERRIDE_STATIC_AUTO) == 0) {
+ return changed;
+ }
- RNA_property_collection_begin(a, iterprop, &iter);
- for (; iter.valid; RNA_property_collection_next(&iter)) {
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ static float _sum_time = 0.0f;
+ static float _num_time = 0.0f;
+ double _timeit_time;
+ if (!root_path) {
+ _timeit_time = PIL_check_seconds_timer();
+ }
+#endif
+
+ iterprop = RNA_struct_iterator_property(local->type);
+
+ for (RNA_property_collection_begin(local, iterprop, &iter); iter.valid; RNA_property_collection_next(&iter)) {
PropertyRNA *prop = iter.ptr.data;
- if (!RNA_property_equals(a, b, prop, mode)) {
- equals = false;
- break;
+ if (!(prop->flag & PROP_OVERRIDABLE)) {
+ continue;
+ }
+ if (RNA_property_animated(local, prop)) {
+ continue;
}
+
+ /* XXX TODO this will have to be refined to handle collections insertions, and array items */
+ char *rna_path;
+ if (root_path) {
+ /* Inlined building, much much more efficient. */
+ rna_path = BLI_sprintfN("%s.%s", root_path, RNA_property_identifier(prop));
+ }
+ else {
+ rna_path = RNA_path_from_ID_to_property(local, prop);
+ }
+ if (rna_path == NULL) {
+ continue;
+ }
+
+ rna_property_override_diff(local, reference, prop, RNA_EQ_STRICT, override, rna_path, &changed,
+ RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN);
+
+ MEM_SAFE_FREE(rna_path);
}
RNA_property_collection_end(&iter);
- return equals;
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ if (!root_path) {
+ const float _delta_time = (float)(PIL_check_seconds_timer() - _timeit_time);
+ _sum_time += _delta_time;
+ _num_time++;
+ printf("ID: %s\n", ((ID *)local->id.data)->name);
+ printf("time end (%s): %.6f\n", __func__, _delta_time);
+ printf("time averaged (%s): %.6f (total: %.6f, in %d runs)\n", __func__, (_sum_time / _num_time), _sum_time, (int)_num_time);
+ }
+#endif
+
+ return changed;
+}
+
+IDOverrideStaticProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop)
+{
+ ID *id = ptr->id.data;
+
+ if (!id || !id->override_static) {
+ return NULL;
+ }
+
+ char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
+ if (rna_path) {
+ IDOverrideStaticProperty *op = BKE_override_static_property_find(id->override_static, rna_path);
+ MEM_freeN(rna_path);
+ return op;
+ }
+ return NULL;
+}
+
+IDOverrideStaticProperty *RNA_property_override_property_get(PointerRNA *ptr, PropertyRNA *prop, bool *r_created)
+{
+ ID *id = ptr->id.data;
+
+ if (!id || !id->override_static) {
+ return NULL;
+ }
+
+ char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
+ if (rna_path) {
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(id->override_static, rna_path, r_created);
+ MEM_freeN(rna_path);
+ return op;
+ }
+ return NULL;
+}
+
+IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_find(
+ PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict)
+{
+ IDOverrideStaticProperty *op = RNA_property_override_property_find(ptr, prop);
+
+ if (!op) {
+ return NULL;
+ }
+
+ return BKE_override_static_property_operation_find(op, NULL, NULL, index, index, strict, r_strict);
}
+IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_get(
+ PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index,
+ const bool strict, bool *r_strict, bool *r_created)
+{
+ IDOverrideStaticProperty *op = RNA_property_override_property_get(ptr, prop, NULL);
+
+ if (!op) {
+ return NULL;
+ }
+
+ return BKE_override_static_property_operation_get(op, operation, NULL, NULL, index, index, strict, r_strict, r_created);
+}
+
+void RNA_property_override_status(
+ PointerRNA *ptr, PropertyRNA *prop, const int index,
+ bool *r_overridable, bool *r_overridden, bool *r_mandatory, bool *r_locked)
+{
+#define SET_RET(_name, _val) if (_name != NULL) *_name = (_val)
+
+ SET_RET(r_overridable, false);
+ SET_RET(r_overridden, false);
+ SET_RET(r_mandatory, false);
+ SET_RET(r_locked, false);
+
+ if (!ptr || !prop || !ptr->id.data || !((ID *)ptr->id.data)->override_static) {
+ return;
+ }
+
+ SET_RET(r_overridable, (prop->flag & PROP_OVERRIDABLE) && (prop->flag & PROP_EDITABLE));
+
+ if (r_overridden || r_mandatory || r_locked) {
+ IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_find(ptr, prop, index, false, NULL);
+ SET_RET(r_overridden, opop != NULL);
+ SET_RET(r_mandatory, (opop->flag & IDOVERRIDESTATIC_FLAG_MANDATORY) != 0);
+ SET_RET(r_locked, (opop->flag & IDOVERRIDESTATIC_FLAG_LOCKED) != 0);
+ }
+}
+
+
bool RNA_path_resolved_create(
PointerRNA *ptr, struct PropertyRNA *prop,
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index c8a6a503fd9..03e58f8f78e 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -1270,6 +1270,14 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier
#endif
}
+ /* Override handling. */
+ if (DefRNA.preprocess) {
+ prop->override_diff = (RNAPropOverrideDiff)"rna_property_override_diff_default";
+ prop->override_store = (RNAPropOverrideStore)"rna_property_override_store_default";
+ prop->override_apply = (RNAPropOverrideApply)"rna_property_override_apply_default";
+ }
+ /* TODO: do we want that for runtime-defined stuff too? I’d say no, but... maybe yes :/ */
+
rna_addtail(&cont->properties, prop);
return prop;
@@ -2222,6 +2230,29 @@ void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editabl
if (editable) prop->itemeditable = (ItemEditableFunc)editable;
}
+/**
+ * Set custom callbacks for override operations handling.
+ *
+ * \note \a diff callback will also be used by RNA comparison/equality functions.
+ */
+void RNA_def_property_override_funcs(PropertyRNA *prop, const char *diff, const char *store, const char *apply)
+{
+ if (!DefRNA.preprocess) {
+ fprintf(stderr, "%s: only during preprocessing.\n", __func__);
+ return;
+ }
+
+ if (diff) {
+ prop->override_diff = (RNAPropOverrideDiff)diff;
+ }
+ if (store) {
+ prop->override_store = (RNAPropOverrideStore)store;
+ }
+ if (apply) {
+ prop->override_apply = (RNAPropOverrideApply)apply;
+ }
+}
+
void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *func)
{
if (!DefRNA.preprocess) {
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 23a34918d33..7dffab4eefb 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -37,6 +37,9 @@
struct FreestyleSettings;
struct ID;
+struct IDOverrideStatic;
+struct IDOverrideStaticProperty;
+struct IDOverrideStaticPropertyOperation;
struct IDProperty;
struct Main;
struct Mesh;
@@ -201,6 +204,12 @@ void RNA_def_mask(struct BlenderRNA *brna);
void rna_def_animdata_common(struct StructRNA *srna);
+bool rna_AnimaData_override_apply(
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage,
+ const int len_local, const int len_reference, const int len_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
void rna_def_animviz_common(struct StructRNA *srna);
void rna_def_motionpath_common(struct StructRNA *srna);
@@ -391,6 +400,33 @@ extern StructRNA RNA_PropertyGroup;
struct IDProperty *rna_idproperty_check(struct PropertyRNA **prop, struct PointerRNA *ptr);
+/* Override default callbacks. */
+/* Default override callbacks for all types. */
+/* TODO: Maybe at some point we'll want to write that in direct RNA-generated code instead
+ * (like we do for default get/set/etc.)?
+ * Not obvious though, those are fairly more complicated than basic SDNA access.
+ */
+int rna_property_override_diff_default(
+ struct PointerRNA *ptr_a, struct PointerRNA *ptr_b,
+ struct PropertyRNA *prop_a, struct PropertyRNA *prop_b,
+ const int len_a, const int len_b,
+ const int mode,
+ struct IDOverrideStatic *override, const char *rna_path,
+ const int flags, bool *r_override_changed);
+
+bool rna_property_override_store_default(
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage,
+ const int len_local, const int len_reference, const int len_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
+bool rna_property_override_apply_default(
+ struct PointerRNA *ptr_dst, struct PointerRNA *ptr_src, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_dst, struct PropertyRNA *prop_src, struct PropertyRNA *prop_storage,
+ const int len_dst, const int len_src, const int len_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
+
/* Builtin Property Callbacks */
void rna_builtin_properties_begin(struct CollectionPropertyIterator *iter, struct PointerRNA *ptr);
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index b43423464e9..fd0b655e41e 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -40,6 +40,9 @@ struct PointerRNA;
struct FunctionRNA;
struct CollectionPropertyIterator;
struct bContext;
+struct IDOverrideStatic;
+struct IDOverrideStaticProperty;
+struct IDOverrideStaticPropertyOperation;
struct IDProperty;
struct GHash;
struct Main;
@@ -117,6 +120,60 @@ typedef void (*PropStringSetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *
typedef int (*PropEnumGetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *prop);
typedef void (*PropEnumSetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *prop, int value);
+/* Handling override operations, and also comparison. */
+enum {
+ /* Do not compare properties that are not overridable. */
+ RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE = 1 << 0,
+ /* Do not compare properties that are already overridden. */
+ RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN = 1 << 1,
+};
+
+/**
+ * If \a override is NULL, merely do comparison between prop_a from ptr_a and prop_b from ptr_b,
+ * following comparison mode given.
+ * If \a override and \a rna_path are not NULL, it will add a new override operation for overridable properties
+ * that differ and have not yet been overridden (and set accordingly \a r_override_changed if given).
+ *
+ * \note Given PropertyRNA are final (in case of IDProps...).
+ * \note In non-array cases, \a len values are 0.
+ * \note \a override, \a rna_path and \a r_override_changed may be NULL pointers.
+ */
+typedef int (*RNAPropOverrideDiff)(
+ struct PointerRNA *ptr_a, struct PointerRNA *ptr_b,
+ struct PropertyRNA *prop_a, struct PropertyRNA *prop_b,
+ const int len_a, const int len_b,
+ const int mode,
+ struct IDOverrideStatic *override, const char *rna_path,
+ const int flags, bool *r_override_changed);
+
+/**
+ * Only used for differential override (add, sub, etc.).
+ * Store into storage the value needed to transform reference's value into local's value.
+ *
+ * \note Given PropertyRNA are final (in case of IDProps...).
+ * \note In non-array cases, \a len values are 0.
+ * \note Might change given override operation (e.g. change 'add' one into 'sub'), in case computed storage value
+ * is out of range (or even change it to basic 'set' operation if nothing else works).
+ */
+typedef bool (*RNAPropOverrideStore)(
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage,
+ const int len_local, const int len_reference, const int len_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
+/**
+ * Apply given override operation from src to dst (using value from storage as second operand
+ * for differential operations).
+ *
+ * \note Given PropertyRNA are final (in case of IDProps...).
+ * \note In non-array cases, \a len values are 0.
+ */
+typedef bool (*RNAPropOverrideApply)(
+ struct PointerRNA *ptr_dst, struct PointerRNA *ptr_src, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_dst, struct PropertyRNA *prop_src, struct PropertyRNA *prop_storage,
+ const int len_dst, const int len_src, const int len_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
/* Container - generic abstracted container of RNA properties */
typedef struct ContainerRNA {
void *next, *prev;
@@ -194,6 +251,11 @@ struct PropertyRNA {
/* callback for testing if array-item editable (if applicable) */
ItemEditableFunc itemeditable;
+ /* Override handling callbacks (diff is also used for comparison). */
+ RNAPropOverrideDiff override_diff;
+ RNAPropOverrideStore override_store;
+ RNAPropOverrideApply override_apply;
+
/* raw access */
int rawoffset;
RawPropertyType rawtype;
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 507262675b3..3bcdd971ed2 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -107,6 +107,8 @@ const EnumPropertyItem rna_enum_property_unit_items[] = {
#include "MEM_guardedalloc.h"
#include "BLI_ghash.h"
+#include "BKE_library_override.h"
+
/* Struct */
static void rna_Struct_identifier_get(PointerRNA *ptr, char *value)
@@ -564,6 +566,13 @@ static int rna_Property_animatable_get(PointerRNA *ptr)
return (prop->flag & PROP_ANIMATABLE) != 0;
}
+static int rna_Property_overridable_get(PointerRNA *ptr)
+{
+ PropertyRNA *prop = (PropertyRNA *)ptr->data;
+
+ return (prop->flag & PROP_OVERRIDABLE) != 0;
+}
+
static int rna_Property_use_output_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
@@ -1082,6 +1091,1001 @@ static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, const char *key
return false;
}
+/* Default override (and compare) callbacks. */
+
+/* Used for both Pointer and Collection properties. */
+static int rna_property_override_equals_propptr(
+ PointerRNA *propptr_a, PointerRNA *propptr_b, eRNACompareMode mode,
+ IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags)
+{
+ bool is_id = false;
+ bool is_type_null = false;
+
+ /* Beware, PointerRNA_NULL has no type and is considered a 'blank page'! */
+ if (propptr_a->type == NULL) {
+ if (propptr_b->type == NULL) {
+ if (r_override_changed) {
+ *r_override_changed = false;
+ }
+ return 0;
+ }
+ is_id = RNA_struct_is_ID(propptr_b->type);
+ is_type_null = true;
+ }
+ else {
+ is_id = RNA_struct_is_ID(propptr_a->type);
+ is_type_null = (propptr_b->type == NULL);
+ }
+
+ if (is_id) {
+ BLI_assert(propptr_a->data == propptr_a->id.data && propptr_b->data == propptr_b->id.data);
+ }
+
+ if (override) {
+ if (rna_path) {
+ if (is_type_null || is_id) {
+ /* In case this is an ID (or one of the pointers is NULL), do not compare structs!
+ * This is a quite safe path to infinite loop.
+ * Instead, just compare pointers themselves (we assume sub-ID structs cannot loop). */
+ const int comp = (propptr_a->data != propptr_b->data);
+
+ if (comp != 0 && rna_path) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp;
+ }
+ else {
+ const bool changed = RNA_struct_auto_override(propptr_a, propptr_b, override, rna_path);
+ if (r_override_changed) {
+ *r_override_changed = *r_override_changed || changed;
+ }
+ /* XXX Simplification here, if no override was added we assume they are equal,
+ * this may not be good behavior, time will say. */
+ return !changed;
+ }
+ }
+ else {
+ return !RNA_struct_override_matches(
+ propptr_a, propptr_b, override,
+ flags & RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE,
+ flags & RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN);
+ }
+ }
+ else {
+ return !RNA_struct_equals(propptr_a, propptr_b, mode);
+ }
+}
+
+static char *rna_path_collection_prop_item_extend(const char *rna_path_prop, const char *item_name)
+{
+ const size_t esc_item_name_len = strlen(item_name) * 2;
+ char *esc_item_name = alloca(sizeof(*esc_item_name) * esc_item_name_len);
+ BLI_strescape(esc_item_name, item_name, esc_item_name_len);
+ return BLI_sprintfN("%s[\"%s\"]", rna_path_prop, esc_item_name);
+}
+
+int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
+ PropertyRNA *prop_a, PropertyRNA *prop_b,
+ const int len_a, const int len_b,
+ const int mode,
+ IDOverrideStatic *override, const char *rna_path,
+ const int flags, bool *r_override_changed)
+{
+ BLI_assert(len_a == len_b);
+
+ switch (RNA_property_type(prop_a)) {
+ case PROP_BOOLEAN:
+ {
+ if (len_a) {
+ int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ int *array_a, *array_b;
+
+ array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_a, "RNA equals") : array_stack_a;
+ array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_b, "RNA equals") : array_stack_b;
+
+ RNA_property_boolean_get_array(ptr_a, prop_a, array_a);
+ RNA_property_boolean_get_array(ptr_b, prop_b, array_b);
+
+ const int comp = memcmp(array_a, array_b, sizeof(int) * len_a);
+
+ if (comp != 0 && rna_path) {
+ /* XXX TODO this will have to be refined to handle array items */
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) {
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ else {
+ /* Already overriden prop, we'll have to check arrays items etc. */
+ }
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+
+ return comp;
+ }
+ else {
+ const int value_a = RNA_property_boolean_get(ptr_a, prop_a);
+ const int value_b = RNA_property_boolean_get(ptr_b, prop_b);
+ const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
+
+ if (comp != 0 && rna_path) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp;
+ }
+ }
+
+ case PROP_INT:
+ {
+ if (len_a) {
+ int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ int *array_a, *array_b;
+
+ array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_a, "RNA equals") : array_stack_a;
+ array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_b, "RNA equals") : array_stack_b;
+
+ RNA_property_int_get_array(ptr_a, prop_a, array_a);
+ RNA_property_int_get_array(ptr_b, prop_b, array_b);
+
+ const int comp = memcmp(array_a, array_b, sizeof(int) * len_a);
+
+ if (comp != 0 && rna_path) {
+ /* XXX TODO this will have to be refined to handle array items */
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) {
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ else {
+ /* Already overriden prop, we'll have to check arrays items etc. */
+ }
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+
+ return comp;
+ }
+ else {
+ const int value_a = RNA_property_int_get(ptr_a, prop_a);
+ const int value_b = RNA_property_int_get(ptr_b, prop_b);
+ const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
+
+ if (comp != 0 && rna_path) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp;
+ }
+ }
+
+ case PROP_FLOAT:
+ {
+ const bool is_proportional = (prop_a->flag & PROP_PROPORTIONAL) != 0;
+ if (len_a) {
+ float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ float *array_a, *array_b;
+
+ array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(float) * len_a, "RNA equals") : array_stack_a;
+ array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(float) * len_b, "RNA equals") : array_stack_b;
+
+ RNA_property_float_get_array(ptr_a, prop_a, array_a);
+ RNA_property_float_get_array(ptr_b, prop_b, array_b);
+
+ const int comp = memcmp(array_a, array_b, sizeof(float) * len_a);
+
+ if (comp != 0 && rna_path) {
+ /* XXX TODO this will have to be refined to handle array items */
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) {
+ BKE_override_static_property_operation_get(
+ op, is_proportional ? IDOVERRIDESTATIC_OP_MULTIPLY : IDOVERRIDESTATIC_OP_REPLACE,
+ NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ else {
+ /* Already overriden prop, we'll have to check arrays items etc. */
+ }
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+
+ return comp;
+ }
+ else {
+ const float value_a = RNA_property_float_get(ptr_a, prop_a);
+ const float value_b = RNA_property_float_get(ptr_b, prop_b);
+ const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
+
+ if (comp != 0 && rna_path) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, is_proportional ? IDOVERRIDESTATIC_OP_MULTIPLY : IDOVERRIDESTATIC_OP_REPLACE,
+ NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp ;
+ }
+ }
+
+ case PROP_ENUM:
+ {
+ const int value_a = RNA_property_enum_get(ptr_a, prop_a);
+ const int value_b = RNA_property_enum_get(ptr_b, prop_b);
+ const int comp = value_a != value_b;
+
+ if (comp != 0 && rna_path) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp;
+ }
+
+ case PROP_STRING:
+ {
+ char fixed_a[128], fixed_b[128];
+ int len_str_a, len_str_b;
+ char *value_a = RNA_property_string_get_alloc(ptr_a, prop_a, fixed_a, sizeof(fixed_a), &len_str_a);
+ char *value_b = RNA_property_string_get_alloc(ptr_b, prop_b, fixed_b, sizeof(fixed_b), &len_str_b);
+ const int comp = strcmp(value_a, value_b);
+
+ if (comp != 0 && rna_path) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ if (value_a != fixed_a) MEM_freeN(value_a);
+ if (value_b != fixed_b) MEM_freeN(value_b);
+
+ return comp;
+ }
+
+ case PROP_POINTER:
+ {
+ if (STREQ(RNA_property_identifier(prop_a), "rna_type")) {
+ /* Dummy 'pass' answer, this is a meta-data and must be ignored... */
+ return 0;
+ }
+ else {
+ PointerRNA propptr_a = RNA_property_pointer_get(ptr_a, prop_a);
+ PointerRNA propptr_b = RNA_property_pointer_get(ptr_b, prop_b);
+ return rna_property_override_equals_propptr(
+ &propptr_a, &propptr_b, mode,
+ override, rna_path, r_override_changed, flags);
+ }
+ break;
+ }
+
+ case PROP_COLLECTION:
+ {
+ bool equals = true;
+ int idx = 0;
+
+ CollectionPropertyIterator iter_a, iter_b;
+ RNA_property_collection_begin(ptr_a, prop_a, &iter_a);
+ RNA_property_collection_begin(ptr_b, prop_b, &iter_b);
+
+ for (; iter_a.valid && iter_b.valid;
+ RNA_property_collection_next(&iter_a), RNA_property_collection_next(&iter_b), idx++)
+ {
+ char *extended_rna_path = NULL;
+
+ if (iter_a.ptr.type != iter_b.ptr.type) {
+ /* nothing we can do (for until we support adding/removing from collections), skip it. */
+ equals = false;
+ continue;
+ }
+
+ PropertyRNA *propname = RNA_struct_name_property(iter_a.ptr.type);
+ char propname_buff_a[256], propname_buff_b[256];
+ char *propname_a = NULL, *propname_b = NULL;
+
+ if (propname != NULL) {
+ propname_a = RNA_property_string_get_alloc(&iter_a.ptr, propname, propname_buff_a, sizeof(propname_buff_a), NULL);
+ propname_b = RNA_property_string_get_alloc(&iter_b.ptr, propname, propname_buff_b, sizeof(propname_buff_b), NULL);
+ if (!STREQ(propname_a, propname_b)) {
+ /* Same as above, not same structs. */
+ equals = false;
+ }
+ else if (rna_path) {
+ extended_rna_path = rna_path_collection_prop_item_extend(rna_path, propname_a);
+ }
+ }
+ else { /* Based on index... */
+ if (rna_path) {
+ extended_rna_path = BLI_sprintfN("%s[%d]", rna_path, idx);
+ }
+ }
+
+ if (equals) {
+ const int eq = rna_property_override_equals_propptr(
+ &iter_a.ptr, &iter_b.ptr, mode,
+ override, extended_rna_path, r_override_changed, flags);
+ equals = equals && eq;
+ }
+
+ if (propname_a != propname_buff_a) {
+ MEM_freeN(propname_a);
+ }
+ if (propname_b != propname_buff_b) {
+ MEM_freeN(propname_b);
+ }
+ MEM_SAFE_FREE(extended_rna_path);
+
+ if (!rna_path && !equals) {
+ break; /* Early out in case we do not want to loop over whole collection. */
+ }
+ }
+
+ equals = equals && !(iter_a.valid || iter_b.valid); /* Not same number of items in both collections... */
+ RNA_property_collection_end(&iter_a);
+ RNA_property_collection_end(&iter_b);
+
+ return (equals == false);
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+bool rna_property_override_store_default(
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage,
+ PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage,
+ const int len_local, const int len_reference, const int len_storage,
+ IDOverrideStaticPropertyOperation *opop)
+{
+ BLI_assert(len_local == len_reference && (!ptr_storage || len_local == len_storage));
+
+ bool changed = false;
+ const int index = opop->subitem_reference_index;
+
+ if (!ELEM(opop->operation, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY)) {
+ return changed;
+ }
+
+ /* XXX TODO About range limits.
+ * Ideally, it woudl be great to get rid of RNA range in that specific case.
+ * However, this won't be that easy and will add yet another layer of complexity in generated code,
+ * not to mention that we could most likely *not* bypass custom setters anyway.
+ * So for now, if needed second operand value is not in valid range, we simply fall back
+ * to a mere REPLACE operation.
+ * Time will say whether this is acceptable limitation or not. */
+ switch (RNA_property_type(prop_local)) {
+ case PROP_BOOLEAN:
+ /* TODO support boolean ops? Really doubt this would ever be useful though... */
+ BLI_assert(0 && "Boolean properties support no override diff operation");
+ break;
+ case PROP_INT:
+ {
+ int prop_min, prop_max;
+ RNA_property_int_range(ptr_local, prop_local, &prop_min, &prop_max);
+
+ if (len_local) {
+ if (index == -1) {
+ int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ int *array_a, *array_b;
+
+ array_a = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_local, __func__) : array_stack_a;
+ RNA_property_int_get_array(ptr_reference, prop_reference, array_a);
+
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const int fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1 : -1;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ bool do_set = true;
+ array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b;
+ RNA_property_int_get_array(ptr_local, prop_local, array_b);
+ for (int i = len_local; i--;) {
+ array_b[i] = fac * (array_b[i] - array_a[i]);
+ if (array_b[i] < prop_min || array_b[i] > prop_max) {
+ opop->operation = other_op;
+ for (int j = len_local; j--;) {
+ array_b[j] = j >= i ? -array_b[j] : fac * (array_a[j] - array_b[j]);
+ if (array_b[j] < prop_min || array_b[j] > prop_max) {
+ /* We failed to find a suitable diff op,
+ * fall back to plain REPLACE one. */
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ do_set = false;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if (do_set) {
+ changed = true;
+ RNA_property_int_set_array(ptr_storage, prop_storage, array_b);
+ }
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on integer");
+ break;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const int value = RNA_property_int_get_index(ptr_reference, prop_reference, index);
+
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const int fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1 : -1;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ int b = fac * (RNA_property_int_get_index(ptr_local, prop_local, index) - value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = other_op;
+ b = -b;
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ }
+ changed = true;
+ RNA_property_int_set_index(ptr_storage, prop_storage, index, b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on integer");
+ break;
+ }
+ }
+ }
+ else {
+ const int value = RNA_property_int_get(ptr_reference, prop_reference);
+
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const int fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1 : -1;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ int b = fac * (RNA_property_int_get(ptr_local, prop_local) - value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = other_op;
+ b = -b;
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ }
+ changed = true;
+ RNA_property_int_set(ptr_storage, prop_storage, b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on integer");
+ break;
+ }
+ }
+ break;
+ }
+ case PROP_FLOAT:
+ {
+ float prop_min, prop_max;
+ RNA_property_float_range(ptr_local, prop_local, &prop_min, &prop_max);
+
+ if (len_local) {
+ if (index == -1) {
+ float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ float *array_a, *array_b;
+
+ array_a = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_local, __func__) : array_stack_a;
+
+ RNA_property_float_get_array(ptr_reference, prop_reference, array_a);
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const float fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1.0 : -1.0;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ bool do_set = true;
+ array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b;
+ RNA_property_float_get_array(ptr_local, prop_local, array_b);
+ for (int i = len_local; i--;) {
+ array_b[i] = fac * (array_b[i] - array_a[i]);
+ if (array_b[i] < prop_min || array_b[i] > prop_max) {
+ opop->operation = other_op;
+ for (int j = len_local; j--;) {
+ array_b[j] = j >= i ? -array_b[j] : fac * (array_a[j] - array_b[j]);
+ if (array_b[j] < prop_min || array_b[j] > prop_max) {
+ /* We failed to find a suitable diff op,
+ * fall back to plain REPLACE one. */
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ do_set = false;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if (do_set) {
+ changed = true;
+ RNA_property_float_set_array(ptr_storage, prop_storage, array_b);
+ }
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ }
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ {
+ bool do_set = true;
+ array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b;
+ RNA_property_float_get_array(ptr_local, prop_local, array_b);
+ for (int i = len_local; i--;) {
+ array_b[i] = array_a[i] == 0.0f ? array_b[i] : array_b[i] / array_a[i];
+ if (array_b[i] < prop_min || array_b[i] > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ do_set = false;
+ break;
+ }
+ }
+ if (do_set) {
+ changed = true;
+ RNA_property_float_set_array(ptr_storage, prop_storage, array_b);
+ }
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on float");
+ break;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const float value = RNA_property_float_get_index(ptr_reference, prop_reference, index);
+
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const float fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1.0f : -1.0f;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ float b = fac * (RNA_property_float_get_index(ptr_local, prop_local, index) - value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = other_op;
+ b = -b;
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ }
+ changed = true;
+ RNA_property_float_set_index(ptr_storage, prop_storage, index, b);
+ break;
+ }
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ {
+ const float b = RNA_property_float_get_index(ptr_local, prop_local, index) / (value == 0.0f ? 1.0f : value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ changed = true;
+ RNA_property_float_set_index(ptr_storage, prop_storage, index, b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on float");
+ break;
+ }
+ }
+ }
+ else {
+ const float value = RNA_property_float_get(ptr_reference, prop_reference);
+
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const float fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1.0f : -1.0f;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ float b = fac * (RNA_property_float_get(ptr_local, prop_local) - value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = other_op;
+ b = -b;
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ }
+ changed = true;
+ RNA_property_float_set(ptr_storage, prop_storage, b);
+ break;
+ }
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ {
+ const float b = RNA_property_float_get(ptr_local, prop_local) / (value == 0.0f ? 1.0f : value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ changed = true;
+ RNA_property_float_set(ptr_storage, prop_storage, b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on float");
+ break;
+ }
+ }
+ return true;
+ }
+ case PROP_ENUM:
+ /* TODO support add/sub, for bitflags? */
+ BLI_assert(0 && "Enum properties support no override diff operation");
+ break;
+ case PROP_POINTER:
+ BLI_assert(0 && "Pointer properties support no override diff operation");
+ break;
+ case PROP_STRING:
+ BLI_assert(0 && "String properties support no override diff operation");
+ break;
+ case PROP_COLLECTION:
+ /* XXX TODO support this of course... */
+ BLI_assert(0 && "Collection properties support no override diff operation");
+ break;
+ default:
+ break;
+ }
+
+ return changed;
+}
+
+bool rna_property_override_apply_default(
+ PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *ptr_storage,
+ PropertyRNA *prop_dst, PropertyRNA *prop_src, PropertyRNA *prop_storage,
+ const int len_dst, const int len_src, const int len_storage,
+ IDOverrideStaticPropertyOperation *opop)
+{
+ BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage));
+
+ const int index = opop->subitem_reference_index;
+ const short override_op = opop->operation;
+
+ switch (RNA_property_type(prop_dst)) {
+ case PROP_BOOLEAN:
+ if (len_dst) {
+ if (index == -1) {
+ int array_stack_a[RNA_STACK_ARRAY];
+ int *array_a;
+
+ array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a;
+
+ RNA_property_boolean_get_array(ptr_src, prop_src, array_a);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_boolean_set_array(ptr_dst, prop_dst, array_a);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on boolean");
+ return false;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const int value = RNA_property_boolean_get_index(ptr_src, prop_src, index);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_boolean_set_index(ptr_dst, prop_dst, index, value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on boolean");
+ return false;
+ }
+ }
+ }
+ else {
+ const int value = RNA_property_boolean_get(ptr_src, prop_src);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_boolean_set(ptr_dst, prop_dst, value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on boolean");
+ return false;
+ }
+ }
+ return true;
+ case PROP_INT:
+ if (len_dst) {
+ if (index == -1) {
+ int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ int *array_a, *array_b;
+
+ array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_int_get_array(ptr_src, prop_src, array_a);
+ RNA_property_int_set_array(ptr_dst, prop_dst, array_a);
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ RNA_property_int_get_array(ptr_dst, prop_dst, array_a);
+ array_b = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_dst, __func__) : array_stack_b;
+ RNA_property_int_get_array(ptr_storage, prop_storage, array_b);
+ if (override_op == IDOVERRIDESTATIC_OP_ADD) {
+ for (int i = len_dst; i--;) array_a[i] += array_b[i];
+ }
+ else {
+ for (int i = len_dst; i--;) array_a[i] -= array_b[i];
+ }
+ RNA_property_int_set_array(ptr_dst, prop_dst, array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on integer");
+ return false;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const int storage_value = ptr_storage ? RNA_property_int_get_index(ptr_storage, prop_storage, index) : 0;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_int_set_index(ptr_dst, prop_dst, index,
+ RNA_property_int_get_index(ptr_src, prop_src, index));
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ RNA_property_int_set_index(ptr_dst, prop_dst, index,
+ RNA_property_int_get_index(ptr_dst, prop_dst, index) - storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ RNA_property_int_set_index(ptr_dst, prop_dst, index,
+ RNA_property_int_get_index(ptr_dst, prop_dst, index) - storage_value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on integer");
+ return false;
+ }
+ }
+ }
+ else {
+ const int storage_value = ptr_storage ? RNA_property_int_get(ptr_storage, prop_storage) : 0;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_int_set(ptr_dst, prop_dst, RNA_property_int_get(ptr_src, prop_src));
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ RNA_property_int_set(ptr_dst, prop_dst, RNA_property_int_get(ptr_dst, prop_dst) + storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ RNA_property_int_set(ptr_dst, prop_dst, RNA_property_int_get(ptr_dst, prop_dst) - storage_value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on integer");
+ return false;
+ }
+ }
+ return true;
+ case PROP_FLOAT:
+ if (len_dst) {
+ if (index == -1) {
+ float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ float *array_a, *array_b;
+
+ array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_float_get_array(ptr_src, prop_src, array_a);
+ RNA_property_float_set_array(ptr_dst, prop_dst, array_a);
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ RNA_property_float_get_array(ptr_dst, prop_dst, array_a);
+ array_b = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_dst, __func__) : array_stack_b;
+ RNA_property_float_get_array(ptr_storage, prop_storage, array_b);
+ if (override_op == IDOVERRIDESTATIC_OP_ADD) {
+ for (int i = len_dst; i--;) array_a[i] += array_b[i];
+ }
+ else if (override_op == IDOVERRIDESTATIC_OP_SUBTRACT) {
+ for (int i = len_dst; i--;) array_a[i] -= array_b[i];
+ }
+ else {
+ for (int i = len_dst; i--;) array_a[i] *= array_b[i];
+ }
+ RNA_property_float_set_array(ptr_dst, prop_dst, array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on float");
+ return false;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const float storage_value = ptr_storage ? RNA_property_float_get_index(ptr_storage, prop_storage, index) : 0.0f;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_float_set_index(ptr_dst, prop_dst, index,
+ RNA_property_float_get_index(ptr_src, prop_src, index));
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ RNA_property_float_set_index(ptr_dst, prop_dst, index,
+ RNA_property_float_get_index(ptr_dst, prop_dst, index) + storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ RNA_property_float_set_index(ptr_dst, prop_dst, index,
+ RNA_property_float_get_index(ptr_dst, prop_dst, index) - storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ RNA_property_float_set_index(ptr_dst, prop_dst, index,
+ RNA_property_float_get_index(ptr_dst, prop_dst, index) * storage_value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on float");
+ return false;
+ }
+ }
+ }
+ else {
+ const float storage_value = ptr_storage ? RNA_property_float_get(ptr_storage, prop_storage) : 0.0f;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_float_set(ptr_dst, prop_dst, RNA_property_float_get(ptr_src, prop_src));
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ RNA_property_float_set(ptr_dst, prop_dst, RNA_property_float_get(ptr_dst, prop_dst) + storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ RNA_property_float_set(ptr_dst, prop_dst, RNA_property_float_get(ptr_dst, prop_dst) - storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ RNA_property_float_set(ptr_dst, prop_dst, RNA_property_float_get(ptr_dst, prop_dst) * storage_value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on float");
+ return false;
+ }
+ }
+ return true;
+ case PROP_ENUM:
+ {
+ const int value = RNA_property_enum_get(ptr_src, prop_src);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_enum_set(ptr_dst, prop_dst, value);
+ break;
+ /* TODO support add/sub, for bitflags? */
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on enum");
+ return false;
+ }
+ return true;
+ }
+ case PROP_POINTER:
+ {
+ PointerRNA value = RNA_property_pointer_get(ptr_src, prop_src);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_pointer_set(ptr_dst, prop_dst, value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on pointer");
+ return false;
+ }
+ return true;
+ }
+ case PROP_STRING:
+ {
+ char buff[256];
+ char *value = RNA_property_string_get_alloc(ptr_src, prop_src, buff, sizeof(buff), NULL);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_string_set(ptr_dst, prop_dst, value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on string");
+ return false;
+ }
+
+ if (value != buff) MEM_freeN(value);
+ return true;
+ }
+ default:
+ /* TODO PROP_COLLECTION of course! */
+ return false;
+ }
+
+ return false;
+}
+
+
#else
@@ -1259,6 +2263,11 @@ static void rna_def_property(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, "rna_Property_animatable_get", NULL);
RNA_def_property_ui_text(prop, "Animatable", "Property is animatable through RNA");
+ prop = RNA_def_property(srna, "is_overridable", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_Property_overridable_get", NULL);
+ RNA_def_property_ui_text(prop, "Overridable", "Property is overridable through RNA");
+
prop = RNA_def_property(srna, "is_required", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Property_is_required_get", NULL);