diff options
Diffstat (limited to 'source/blender/makesrna/intern/rna_access_compare_override.c')
-rw-r--r-- | source/blender/makesrna/intern/rna_access_compare_override.c | 336 |
1 files changed, 199 insertions, 137 deletions
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index 265e83ddcba..0a739dcfc5a 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -18,17 +18,20 @@ * \ingroup RNA */ +#include <string.h> + #include "MEM_guardedalloc.h" #include "DNA_ID.h" #include "DNA_constraint_types.h" +#include "DNA_key_types.h" #include "DNA_modifier_types.h" #include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_utildefines.h" -// #define DEBUG_OVERRIDE_TIMEIT +//#define DEBUG_OVERRIDE_TIMEIT #ifdef DEBUG_OVERRIDE_TIMEIT # include "PIL_time_utildefines.h" @@ -58,7 +61,7 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop) /* Special handling for insertions of constraints or modifiers... */ /* TODO Note We may want to add a more generic system to RNA * (like a special property in struct of items) - * if we get more override-able collections, + * if we get more overrideable collections, * for now we can live with those special-cases handling I think. */ if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) { bConstraint *con = ptr->data; @@ -106,7 +109,7 @@ bool RNA_property_overridden(PointerRNA *ptr, PropertyRNA *prop) char *rna_path = RNA_path_from_ID_to_property(ptr, prop); ID *id = ptr->owner_id; - if (rna_path == NULL || id == NULL || id->override_library == NULL) { + if (rna_path == NULL || id == NULL || !ID_IS_OVERRIDE_LIBRARY(id)) { return false; } @@ -174,15 +177,13 @@ bool RNA_property_copy( } static int rna_property_override_diff(Main *bmain, - PointerRNA *ptr_a, - PointerRNA *ptr_b, - PropertyRNA *prop, - PropertyRNA *prop_a, - PropertyRNA *prop_b, + PropertyRNAOrID *prop_a, + PropertyRNAOrID *prop_b, const char *rna_path, + const size_t rna_path_len, eRNACompareMode mode, IDOverrideLibrary *override, - const int flags, + const eRNAOverrideMatch flags, eRNAOverrideMatchResult *r_report_flags); bool RNA_property_equals( @@ -190,8 +191,12 @@ bool RNA_property_equals( { BLI_assert(ELEM(mode, RNA_EQ_STRICT, RNA_EQ_UNSET_MATCH_ANY, RNA_EQ_UNSET_MATCH_NONE)); - return (rna_property_override_diff( - bmain, ptr_a, ptr_b, prop, NULL, NULL, NULL, mode, NULL, 0, NULL) == 0); + PropertyRNAOrID prop_a, prop_b; + + rna_property_rna_or_id_get(prop, ptr_a, &prop_a); + rna_property_rna_or_id_get(prop, ptr_b, &prop_b); + + return (rna_property_override_diff(bmain, &prop_a, &prop_b, NULL, 0, mode, NULL, 0, NULL) == 0); } bool RNA_struct_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACompareMode mode) @@ -243,58 +248,42 @@ bool RNA_struct_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACo * but we cannot determine an order (greater than/lesser than), we return 1. */ static int rna_property_override_diff(Main *bmain, - PointerRNA *ptr_a, - PointerRNA *ptr_b, - PropertyRNA *prop, - PropertyRNA *prop_a, - PropertyRNA *prop_b, + PropertyRNAOrID *prop_a, + PropertyRNAOrID *prop_b, const char *rna_path, + const size_t rna_path_len, eRNACompareMode mode, IDOverrideLibrary *override, - const int flags, + const eRNAOverrideMatch flags, eRNAOverrideMatchResult *r_report_flags) { - if (prop != NULL) { - BLI_assert(prop_a == NULL && prop_b == NULL); - prop_a = prop; - prop_b = prop; - } + BLI_assert(!ELEM(NULL, prop_a, prop_b)); - if (ELEM(NULL, prop_a, prop_b)) { - return (prop_a == prop_b) ? 0 : 1; - } - - if (!RNA_property_comparable(ptr_a, prop_a) || !RNA_property_comparable(ptr_b, prop_b)) { + if (prop_a->rnaprop->flag_override & PROPOVERRIDE_NO_COMPARISON || + prop_b->rnaprop->flag_override & PROPOVERRIDE_NO_COMPARISON) { return 0; } if (mode == RNA_EQ_UNSET_MATCH_ANY) { - /* uninitialized properties are assumed to match anything */ - if (!RNA_property_is_set(ptr_a, prop_a) || !RNA_property_is_set(ptr_b, prop_b)) { + /* Unset properties are assumed to match anything. */ + if (!prop_a->is_set || !prop_b->is_set) { return 0; } } else if (mode == RNA_EQ_UNSET_MATCH_NONE) { - /* unset properties never match set properties */ - if (RNA_property_is_set(ptr_a, prop_a) != RNA_property_is_set(ptr_b, prop_b)) { + /* Unset properties never match set properties. */ + if (prop_a->is_set != prop_b->is_set) { return 1; } } - if (prop != NULL) { - /* Ensure we get real property data, be it an actual RNA property, - * or an IDProperty in disguise. */ - prop_a = rna_ensure_property_realdata(&prop_a, ptr_a); - prop_b = rna_ensure_property_realdata(&prop_b, ptr_b); - - if (ELEM(NULL, prop_a, prop_b)) { - return (prop_a == prop_b) ? 0 : 1; - } + if (prop_a->is_idprop && ELEM(NULL, prop_a->idprop, prop_b->idprop)) { + return (prop_a->idprop == prop_b->idprop) ? 0 : 1; } /* Check if we are working with arrays. */ - const bool is_array_a = RNA_property_array_check(prop_a); - const bool is_array_b = RNA_property_array_check(prop_b); + const bool is_array_a = prop_a->is_array; + const bool is_array_b = prop_b->is_array; if (is_array_a != is_array_b) { /* Should probably never happen actually... */ @@ -303,8 +292,8 @@ static int rna_property_override_diff(Main *bmain, } /* Get the length of the array to work with. */ - const int len_a = RNA_property_array_length(ptr_a, prop_a); - const int len_b = RNA_property_array_length(ptr_b, prop_b); + const uint len_a = prop_a->array_len; + const uint len_b = prop_b->array_len; if (len_a != len_b) { /* Do not handle override in that case, @@ -319,50 +308,48 @@ static int rna_property_override_diff(Main *bmain, RNAPropOverrideDiff override_diff = NULL; /* Special case for IDProps, we use default callback then. */ - if (prop_a->magic != RNA_MAGIC) { + if (prop_a->is_idprop) { override_diff = rna_property_override_diff_default; - if (prop_b->magic == RNA_MAGIC && prop_b->override_diff != override_diff) { + if (!prop_b->is_idprop && prop_b->rnaprop->override_diff != override_diff) { override_diff = NULL; } } - else if (prop_b->magic != RNA_MAGIC) { + else if (prop_b->is_idprop) { override_diff = rna_property_override_diff_default; - if (prop_a->override_diff != override_diff) { + if (prop_a->rnaprop->override_diff != override_diff) { override_diff = NULL; } } - else if (prop_a->override_diff == prop_b->override_diff) { - override_diff = prop_a->override_diff; + else if (prop_a->rnaprop->override_diff == prop_b->rnaprop->override_diff) { + override_diff = prop_a->rnaprop->override_diff; + if (override_diff == NULL) { + override_diff = rna_property_override_diff_default; + } } if (override_diff == NULL) { #ifndef NDEBUG printf("'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d).\n", - rna_path ? - rna_path : - (prop_a->magic != RNA_MAGIC ? ((IDProperty *)prop_a)->name : prop_a->identifier), - prop_a->magic == RNA_MAGIC, - prop_b->magic == RNA_MAGIC); + rna_path ? rna_path : prop_a->identifier, + !prop_a->is_idprop, + !prop_b->is_idprop); #endif BLI_assert(0); return 1; } bool override_changed = false; - int diff_flags = flags; - if (!RNA_property_overridable_get(ptr_a, prop_a)) { + eRNAOverrideMatch diff_flags = flags; + if (!RNA_property_overridable_get(&prop_a->ptr, prop_a->rawprop)) { diff_flags &= ~RNA_OVERRIDE_COMPARE_CREATE; } const int diff = override_diff(bmain, - ptr_a, - ptr_b, prop_a, prop_b, - len_a, - len_b, mode, override, rna_path, + rna_path_len, diff_flags, &override_changed); if (override_changed && r_report_flags) { @@ -420,10 +407,13 @@ static bool rna_property_override_operation_store(Main *bmain, } else if (prop_local->override_store == prop_reference->override_store) { override_store = prop_local->override_store; + if (override_store == NULL) { + override_store = rna_property_override_store_default; + } } if (ptr_storage != NULL && prop_storage->magic == RNA_MAGIC && - prop_storage->override_store != override_store) { + !ELEM(prop_storage->override_store, NULL, override_store)) { override_store = NULL; } @@ -506,10 +496,13 @@ static bool rna_property_override_operation_apply(Main *bmain, } else if (prop_dst->override_apply == prop_src->override_apply) { override_apply = prop_dst->override_apply; + if (override_apply == NULL) { + override_apply = rna_property_override_apply_default; + } } if (ptr_storage && prop_storage->magic == RNA_MAGIC && - prop_storage->override_apply != override_apply) { + !ELEM(prop_storage->override_apply, NULL, override_apply)) { override_apply = NULL; } @@ -568,6 +561,7 @@ bool RNA_struct_override_matches(Main *bmain, PointerRNA *ptr_local, PointerRNA *ptr_reference, const char *root_path, + const size_t root_path_len, IDOverrideLibrary *override, const eRNAOverrideMatch flags, eRNAOverrideMatchResult *r_report_flags) @@ -605,38 +599,29 @@ bool RNA_struct_override_matches(Main *bmain, for (RNA_property_collection_begin(ptr_local, iterprop, &iter); iter.valid; RNA_property_collection_next(&iter)) { - PropertyRNA *prop_local = iter.ptr.data; - PropertyRNA *prop_reference = iter.ptr.data; - - /* Ensure we get real property data, be it an actual RNA property, - * or an IDProperty in disguise. */ - prop_local = rna_ensure_property_realdata(&prop_local, ptr_local); - prop_reference = rna_ensure_property_realdata(&prop_reference, ptr_reference); - - /* IDProps (custom properties) are even more of a PITA here, we cannot use - * `rna_ensure_property_realdata()` to deal with them, we have to use the path generated from - * `prop_local` (which is valid) to access to the actual reference counterpart... */ - if (prop_local != NULL && prop_local->magic != RNA_MAGIC && prop_local == prop_reference) { - /* We could also use (lower in this code, after rna_path has been computed): - * RNA_path_resolve_property(ptr_reference, rna_path, &some_rna_ptr, &prop_reference); - * But that would be much more costly, and would also fail when ptr_reference - * is not an ID pointer itself, so we'd need to rebuild it from its owner_id, then check that - * generated some_rna_ptr and ptr_reference do point to the same data, etc. - * For now, let's try that simple access, it won't cover all cases but should handle fine - * most basic custom properties situations. */ - prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, - ((IDProperty *)prop_local)->name); - } + PropertyRNA *rawprop = iter.ptr.data; + + PropertyRNAOrID prop_local; + PropertyRNAOrID prop_reference; + + rna_property_rna_or_id_get(rawprop, ptr_local, &prop_local); + rna_property_rna_or_id_get(rawprop, ptr_reference, &prop_reference); + + BLI_assert(prop_local.rnaprop != NULL); + BLI_assert(prop_local.rnaprop == prop_reference.rnaprop); + BLI_assert(prop_local.is_idprop == prop_reference.is_idprop); - if (ELEM(NULL, prop_local, prop_reference)) { + if ((prop_local.is_idprop && prop_local.idprop == NULL) || + (prop_reference.is_idprop && prop_reference.idprop == NULL)) { continue; } - if (ignore_non_overridable && !RNA_property_overridable_get(ptr_local, prop_local)) { + if (ignore_non_overridable && !RNA_property_overridable_get(&prop_local.ptr, rawprop)) { continue; } - if (RNA_property_override_flag(prop_local) & PROPOVERRIDE_IGNORE) { + if (!prop_local.is_idprop && + RNA_property_override_flag(prop_local.rnaprop) & PROPOVERRIDE_IGNORE) { continue; } @@ -649,31 +634,51 @@ bool RNA_struct_override_matches(Main *bmain, #endif #define RNA_PATH_BUFFSIZE 8192 -#define RNA_PATH_PRINTF(_str, ...) \ - if (BLI_snprintf(rna_path, RNA_PATH_BUFFSIZE, (_str), __VA_ARGS__) >= RNA_PATH_BUFFSIZE) { \ - rna_path = BLI_sprintfN((_str), __VA_ARGS__); \ - } \ - (void)0 -#define RNA_PATH_FREE \ - if (rna_path != rna_path_buffer) \ - MEM_freeN(rna_path) char rna_path_buffer[RNA_PATH_BUFFSIZE]; char *rna_path = rna_path_buffer; + size_t rna_path_len = 0; /* XXX TODO this will have to be refined to handle collections insertions, and array items */ if (root_path) { + BLI_assert(strlen(root_path) == root_path_len); + + const char *prop_name = prop_local.identifier; + const size_t prop_name_len = strlen(prop_name); + /* Inlined building, much much more efficient. */ - if (prop_local->magic == RNA_MAGIC) { - RNA_PATH_PRINTF("%s.%s", root_path, RNA_property_identifier(prop_local)); + if (!prop_local.is_idprop) { + rna_path_len = root_path_len + 1 + prop_name_len; + if (rna_path_len >= RNA_PATH_BUFFSIZE) { + rna_path = MEM_mallocN(rna_path_len + 1, __func__); + } + + memcpy(rna_path, root_path, root_path_len); + rna_path[root_path_len] = '.'; + memcpy(rna_path + root_path_len + 1, prop_name, prop_name_len); + rna_path[rna_path_len] = '\0'; } else { - RNA_PATH_PRINTF("%s[\"%s\"]", root_path, RNA_property_identifier(prop_local)); + rna_path_len = root_path_len + 2 + prop_name_len + 2; + if (rna_path_len >= RNA_PATH_BUFFSIZE) { + rna_path = MEM_mallocN(rna_path_len + 1, __func__); + } + + memcpy(rna_path, root_path, root_path_len); + rna_path[root_path_len] = '['; + rna_path[root_path_len + 1] = '"'; + memcpy(rna_path + root_path_len + 2, prop_name, prop_name_len); + rna_path[root_path_len + 2 + prop_name_len] = '"'; + rna_path[root_path_len + 2 + prop_name_len + 1] = ']'; + rna_path[rna_path_len] = '\0'; } } else { /* This is rather slow, but is not much called, so not really worth optimizing. */ - rna_path = RNA_path_from_ID_to_property(ptr_local, prop_local); + rna_path = RNA_path_from_ID_to_property(ptr_local, rawprop); + if (rna_path != NULL) { + rna_path_len = strlen(rna_path); + } } if (rna_path == NULL) { continue; @@ -684,7 +689,10 @@ bool RNA_struct_override_matches(Main *bmain, IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(override, rna_path); if (ignore_overridden && op != NULL) { BKE_lib_override_library_operations_tag(op, IDOVERRIDE_LIBRARY_TAG_UNUSED, false); - RNA_PATH_FREE; + + if (rna_path != rna_path_buffer) { + MEM_freeN(rna_path); + } continue; } @@ -696,12 +704,10 @@ bool RNA_struct_override_matches(Main *bmain, eRNAOverrideMatchResult report_flags = 0; const int diff = rna_property_override_diff(bmain, - ptr_local, - ptr_reference, - NULL, - prop_local, - prop_reference, + &prop_local, + &prop_reference, rna_path, + rna_path_len, RNA_EQ_STRICT, override, flags, @@ -733,7 +739,7 @@ bool RNA_struct_override_matches(Main *bmain, /* We are allowed to restore to reference's values. */ if (ELEM(NULL, op, opop) || opop->operation == IDOVERRIDE_LIBRARY_OP_NOOP) { /* We should restore that property to its reference value */ - if (RNA_property_editable(ptr_local, prop_local)) { + if (RNA_property_editable(ptr_local, rawprop)) { IDOverrideLibraryPropertyOperation opop_tmp = { .operation = IDOVERRIDE_LIBRARY_OP_REPLACE, .subitem_reference_index = -1, @@ -743,8 +749,8 @@ bool RNA_struct_override_matches(Main *bmain, ptr_local, ptr_reference, NULL, - prop_local, - prop_reference, + rawprop, + rawprop, NULL, NULL, NULL, @@ -769,17 +775,18 @@ bool RNA_struct_override_matches(Main *bmain, matching = false; if (!(do_create || do_restore)) { /* Since we have no 'changing' action allowed, we can break here. */ - MEM_SAFE_FREE(rna_path); + if (rna_path != rna_path_buffer) { + MEM_freeN(rna_path); + } break; } } } - RNA_PATH_FREE; - + if (rna_path != rna_path_buffer) { + MEM_freeN(rna_path); + } #undef RNA_PATH_BUFFSIZE -#undef RNA_PATH_PRINTF -#undef RNA_PATH_FREE } RNA_property_collection_end(&iter); @@ -1045,36 +1052,87 @@ void RNA_struct_override_apply(Main *bmain, #endif } -IDOverrideLibraryProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop) +static char *rna_property_override_property_real_id_owner(Main *bmain, + PointerRNA *ptr, + PropertyRNA *prop, + ID **r_id) { ID *id = ptr->owner_id; + ID *owner_id = id; + const char *rna_path_prefix = NULL; - if (!id || !id->override_library) { + *r_id = NULL; + + if (id == NULL) { + return NULL; + } + + if (id->flag & (LIB_EMBEDDED_DATA | LIB_EMBEDDED_DATA_LIB_OVERRIDE)) { + /* XXX this is very bad band-aid code, but for now it will do. + * We should at least use a #define for those prop names. + * Ideally RNA as a whole should be aware of those PITA of embedded IDs, and have a way to + * retrieve their owner IDs and generate paths from those. + */ + + switch (GS(id->name)) { + case ID_KE: + owner_id = ((Key *)id)->from; + rna_path_prefix = "shape_keys."; + break; + case ID_GR: + case ID_NT: + /* Master collections, Root node trees. */ + owner_id = RNA_find_real_ID_and_path(bmain, id, &rna_path_prefix); + break; + default: + BLI_assert(0); + } + } + + if (!ID_IS_OVERRIDE_LIBRARY_REAL(owner_id)) { return NULL; } char *rna_path = RNA_path_from_ID_to_property(ptr, prop); if (rna_path) { - IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(id->override_library, - rna_path); + char *rna_path_full = rna_path; + if (rna_path_prefix != NULL) { + rna_path_full = BLI_sprintfN("%s%s", rna_path_prefix, rna_path); + MEM_freeN(rna_path); + } + + *r_id = owner_id; + return rna_path_full; + } + return NULL; +} + +IDOverrideLibraryProperty *RNA_property_override_property_find(Main *bmain, + PointerRNA *ptr, + PropertyRNA *prop, + ID **r_owner_id) +{ + char *rna_path; + + if ((rna_path = rna_property_override_property_real_id_owner(bmain, ptr, prop, r_owner_id)) != + NULL) { + IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find( + (*r_owner_id)->override_library, rna_path); MEM_freeN(rna_path); return op; } return NULL; } -IDOverrideLibraryProperty *RNA_property_override_property_get(PointerRNA *ptr, +IDOverrideLibraryProperty *RNA_property_override_property_get(Main *bmain, + PointerRNA *ptr, PropertyRNA *prop, bool *r_created) { - ID *id = ptr->owner_id; + ID *id; + char *rna_path; - if (!id || !id->override_library) { - return NULL; - } - - char *rna_path = RNA_path_from_ID_to_property(ptr, prop); - if (rna_path) { + if ((rna_path = rna_property_override_property_real_id_owner(bmain, ptr, prop, &id)) != NULL) { IDOverrideLibraryProperty *op = BKE_lib_override_library_property_get( id->override_library, rna_path, r_created); MEM_freeN(rna_path); @@ -1084,9 +1142,15 @@ IDOverrideLibraryProperty *RNA_property_override_property_get(PointerRNA *ptr, } IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_find( - PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict) + Main *bmain, + PointerRNA *ptr, + PropertyRNA *prop, + const int index, + const bool strict, + bool *r_strict) { - IDOverrideLibraryProperty *op = RNA_property_override_property_find(ptr, prop); + ID *owner_id; + IDOverrideLibraryProperty *op = RNA_property_override_property_find(bmain, ptr, prop, &owner_id); if (!op) { return NULL; @@ -1097,6 +1161,7 @@ IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_fin } IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_get( + Main *bmain, PointerRNA *ptr, PropertyRNA *prop, const short operation, @@ -1105,7 +1170,7 @@ IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_get bool *r_strict, bool *r_created) { - IDOverrideLibraryProperty *op = RNA_property_override_property_get(ptr, prop, NULL); + IDOverrideLibraryProperty *op = RNA_property_override_property_get(bmain, ptr, prop, NULL); if (!op) { return NULL; @@ -1115,17 +1180,14 @@ IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_get op, operation, NULL, NULL, index, index, strict, r_strict, r_created); } -eRNAOverrideStatus RNA_property_override_library_status(PointerRNA *ptr, +eRNAOverrideStatus RNA_property_override_library_status(Main *bmain, + PointerRNA *ptr, PropertyRNA *prop, const int index) { - int override_status = 0; - - if (!BKE_lib_override_library_is_enabled()) { - return override_status; - } + uint override_status = 0; - if (!ptr || !prop || !ptr->owner_id || !(ptr->owner_id)->override_library) { + if (!ptr || !prop || !ptr->owner_id || !ID_IS_OVERRIDE_LIBRARY(ptr->owner_id)) { return override_status; } @@ -1134,7 +1196,7 @@ eRNAOverrideStatus RNA_property_override_library_status(PointerRNA *ptr, } IDOverrideLibraryPropertyOperation *opop = RNA_property_override_property_operation_find( - ptr, prop, index, false, NULL); + bmain, ptr, prop, index, false, NULL); if (opop != NULL) { override_status |= RNA_OVERRIDE_STATUS_OVERRIDDEN; if (opop->flag & IDOVERRIDE_LIBRARY_FLAG_MANDATORY) { |