diff options
Diffstat (limited to 'source/blender/blenkernel/intern/library_override.c')
-rw-r--r-- | source/blender/blenkernel/intern/library_override.c | 1015 |
1 files changed, 534 insertions, 481 deletions
diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c index c54f11934e1..7a29575dffe 100644 --- a/source/blender/blenkernel/intern/library_override.c +++ b/source/blender/blenkernel/intern/library_override.c @@ -45,10 +45,12 @@ #include "PIL_time.h" #include "PIL_time_utildefines.h" -#define OVERRIDE_AUTO_CHECK_DELAY 0.2 /* 200ms between auto-override checks. */ +#define OVERRIDE_AUTO_CHECK_DELAY 0.2 /* 200ms between auto-override checks. */ -static void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src); -static void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src); +static void bke_override_property_copy(IDOverrideStaticProperty *op_dst, + IDOverrideStaticProperty *op_src); +static void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, + IDOverrideStaticPropertyOperation *opop_src); static void bke_override_property_clear(IDOverrideStaticProperty *op); static void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop); @@ -58,136 +60,139 @@ static bool _override_static_enabled = false; void BKE_override_static_enable(const bool do_enable) { - _override_static_enabled = do_enable; + _override_static_enabled = do_enable; } bool BKE_override_static_is_enabled() { - return _override_static_enabled; + return _override_static_enabled; } /** Initialize empty overriding of \a reference_id by \a local_id. */ IDOverrideStatic *BKE_override_static_init(ID *local_id, ID *reference_id) { - /* If reference_id is NULL, we are creating an override template for purely local data. - * Else, reference *must* be linked data. */ - BLI_assert(reference_id == NULL || reference_id->lib != NULL); - BLI_assert(local_id->override_static == NULL); - - ID *ancestor_id; - for (ancestor_id = reference_id; - ancestor_id != NULL && ancestor_id->override_static != NULL && ancestor_id->override_static->reference != NULL; - ancestor_id = ancestor_id->override_static->reference); - - if (ancestor_id != NULL && ancestor_id->override_static != NULL) { - /* Original ID has a template, use it! */ - BKE_override_static_copy(local_id, ancestor_id); - if (local_id->override_static->reference != reference_id) { - id_us_min(local_id->override_static->reference); - local_id->override_static->reference = reference_id; - id_us_plus(local_id->override_static->reference); - } - return local_id->override_static; - } - - /* Else, generate new empty override. */ - local_id->override_static = MEM_callocN(sizeof(*local_id->override_static), __func__); - local_id->override_static->reference = reference_id; - id_us_plus(local_id->override_static->reference); - local_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; - /* TODO do we want to add tag or flag to referee to mark it as such? */ - return local_id->override_static; + /* If reference_id is NULL, we are creating an override template for purely local data. + * Else, reference *must* be linked data. */ + BLI_assert(reference_id == NULL || reference_id->lib != NULL); + BLI_assert(local_id->override_static == NULL); + + ID *ancestor_id; + for (ancestor_id = reference_id; ancestor_id != NULL && ancestor_id->override_static != NULL && + ancestor_id->override_static->reference != NULL; + ancestor_id = ancestor_id->override_static->reference) + ; + + if (ancestor_id != NULL && ancestor_id->override_static != NULL) { + /* Original ID has a template, use it! */ + BKE_override_static_copy(local_id, ancestor_id); + if (local_id->override_static->reference != reference_id) { + id_us_min(local_id->override_static->reference); + local_id->override_static->reference = reference_id; + id_us_plus(local_id->override_static->reference); + } + return local_id->override_static; + } + + /* Else, generate new empty override. */ + local_id->override_static = MEM_callocN(sizeof(*local_id->override_static), __func__); + local_id->override_static->reference = reference_id; + id_us_plus(local_id->override_static->reference); + local_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; + /* TODO do we want to add tag or flag to referee to mark it as such? */ + return local_id->override_static; } /** Deep copy of a whole override from \a src_id to \a dst_id. */ void BKE_override_static_copy(ID *dst_id, const ID *src_id) { - BLI_assert(src_id->override_static != NULL); - - if (dst_id->override_static != NULL) { - if (src_id->override_static == NULL) { - BKE_override_static_free(&dst_id->override_static); - return; - } - else { - BKE_override_static_clear(dst_id->override_static); - } - } - else if (src_id->override_static == NULL) { - return; - } - else { - BKE_override_static_init(dst_id, NULL); - } - - /* Source is already overriding data, we copy it but reuse its reference for dest ID. - * otherwise, source is only an override template, it then becomes reference of dest ID. */ - dst_id->override_static->reference = src_id->override_static->reference ? src_id->override_static->reference : (ID *)src_id; - id_us_plus(dst_id->override_static->reference); - - BLI_duplicatelist(&dst_id->override_static->properties, &src_id->override_static->properties); - for (IDOverrideStaticProperty *op_dst = dst_id->override_static->properties.first, *op_src = src_id->override_static->properties.first; - op_dst; - op_dst = op_dst->next, op_src = op_src->next) - { - bke_override_property_copy(op_dst, op_src); - } - - dst_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; + BLI_assert(src_id->override_static != NULL); + + if (dst_id->override_static != NULL) { + if (src_id->override_static == NULL) { + BKE_override_static_free(&dst_id->override_static); + return; + } + else { + BKE_override_static_clear(dst_id->override_static); + } + } + else if (src_id->override_static == NULL) { + return; + } + else { + BKE_override_static_init(dst_id, NULL); + } + + /* Source is already overriding data, we copy it but reuse its reference for dest ID. + * otherwise, source is only an override template, it then becomes reference of dest ID. */ + dst_id->override_static->reference = src_id->override_static->reference ? + src_id->override_static->reference : + (ID *)src_id; + id_us_plus(dst_id->override_static->reference); + + BLI_duplicatelist(&dst_id->override_static->properties, &src_id->override_static->properties); + for (IDOverrideStaticProperty *op_dst = dst_id->override_static->properties.first, + *op_src = src_id->override_static->properties.first; + op_dst; + op_dst = op_dst->next, op_src = op_src->next) { + bke_override_property_copy(op_dst, op_src); + } + + dst_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; } /** Clear any overriding data from given \a override. */ void BKE_override_static_clear(IDOverrideStatic *override) { - BLI_assert(override != NULL); + BLI_assert(override != NULL); - for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) { - bke_override_property_clear(op); - } - BLI_freelistN(&override->properties); + for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) { + bke_override_property_clear(op); + } + BLI_freelistN(&override->properties); - id_us_min(override->reference); - /* override->storage should never be refcounted... */ + id_us_min(override->reference); + /* override->storage should never be refcounted... */ } /** Free given \a override. */ void BKE_override_static_free(struct IDOverrideStatic **override) { - BLI_assert(*override != NULL); + BLI_assert(*override != NULL); - BKE_override_static_clear(*override); - MEM_freeN(*override); - *override = NULL; + BKE_override_static_clear(*override); + MEM_freeN(*override); + *override = NULL; } static ID *override_static_create_from(Main *bmain, ID *reference_id) { - ID *local_id; + ID *local_id; - if (!BKE_id_copy(bmain, reference_id, (ID **)&local_id)) { - return NULL; - } - id_us_min(local_id); + if (!BKE_id_copy(bmain, reference_id, (ID **)&local_id)) { + return NULL; + } + id_us_min(local_id); - BKE_override_static_init(local_id, reference_id); - local_id->override_static->flag |= STATICOVERRIDE_AUTO; + BKE_override_static_init(local_id, reference_id); + local_id->override_static->flag |= STATICOVERRIDE_AUTO; - return local_id; + return local_id; } - /** Create an overridden local copy of linked reference. */ ID *BKE_override_static_create_from_id(Main *bmain, ID *reference_id) { - BLI_assert(reference_id != NULL); - BLI_assert(reference_id->lib != NULL); + BLI_assert(reference_id != NULL); + BLI_assert(reference_id->lib != NULL); - ID *local_id = override_static_create_from(bmain, reference_id); + ID *local_id = override_static_create_from(bmain, reference_id); - /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overridden ID). */ - BKE_libblock_remap(bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE); + /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overridden ID). */ + BKE_libblock_remap( + bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE); - return local_id; + return local_id; } /** Create overridden local copies of all tagged data-blocks in given Main. @@ -199,237 +204,272 @@ ID *BKE_override_static_create_from_id(Main *bmain, ID *reference_id) */ bool BKE_override_static_create_from_tag(Main *bmain) { - ID *reference_id; - bool ret = true; - - FOREACH_MAIN_ID_BEGIN(bmain, reference_id) - { - if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) { - if ((reference_id->newid = override_static_create_from(bmain, reference_id)) == NULL) { - ret = false; - } - } - } - FOREACH_MAIN_ID_END; - - FOREACH_MAIN_ID_BEGIN(bmain, reference_id) - { - if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL && reference_id->newid != NULL) { - ID *local_id = reference_id->newid; - BKE_libblock_remap(bmain, reference_id, local_id, - ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE); - } - } - FOREACH_MAIN_ID_END; - - return ret; + ID *reference_id; + bool ret = true; + + FOREACH_MAIN_ID_BEGIN(bmain, reference_id) + { + if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) { + if ((reference_id->newid = override_static_create_from(bmain, reference_id)) == NULL) { + ret = false; + } + } + } + FOREACH_MAIN_ID_END; + + FOREACH_MAIN_ID_BEGIN(bmain, reference_id) + { + if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL && + reference_id->newid != NULL) { + ID *local_id = reference_id->newid; + BKE_libblock_remap(bmain, + reference_id, + local_id, + ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE); + } + } + FOREACH_MAIN_ID_END; + + return ret; } /** * Find override property from given RNA path, if it exists. */ -IDOverrideStaticProperty *BKE_override_static_property_find(IDOverrideStatic *override, const char *rna_path) +IDOverrideStaticProperty *BKE_override_static_property_find(IDOverrideStatic *override, + const char *rna_path) { - /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */ - return BLI_findstring_ptr(&override->properties, rna_path, offsetof(IDOverrideStaticProperty, rna_path)); + /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */ + return BLI_findstring_ptr( + &override->properties, rna_path, offsetof(IDOverrideStaticProperty, rna_path)); } /** * Find override property from given RNA path, or create it if it does not exist. */ -IDOverrideStaticProperty *BKE_override_static_property_get(IDOverrideStatic *override, const char *rna_path, bool *r_created) +IDOverrideStaticProperty *BKE_override_static_property_get(IDOverrideStatic *override, + const char *rna_path, + bool *r_created) { - /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */ - IDOverrideStaticProperty *op = BKE_override_static_property_find(override, rna_path); - - if (op == NULL) { - op = MEM_callocN(sizeof(IDOverrideStaticProperty), __func__); - op->rna_path = BLI_strdup(rna_path); - BLI_addtail(&override->properties, op); - - if (r_created) { - *r_created = true; - } - } - else if (r_created) { - *r_created = false; - } - - return op; + /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */ + IDOverrideStaticProperty *op = BKE_override_static_property_find(override, rna_path); + + if (op == NULL) { + op = MEM_callocN(sizeof(IDOverrideStaticProperty), __func__); + op->rna_path = BLI_strdup(rna_path); + BLI_addtail(&override->properties, op); + + if (r_created) { + *r_created = true; + } + } + else if (r_created) { + *r_created = false; + } + + return op; } void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src) { - op_dst->rna_path = BLI_strdup(op_src->rna_path); - BLI_duplicatelist(&op_dst->operations, &op_src->operations); - - for (IDOverrideStaticPropertyOperation *opop_dst = op_dst->operations.first, *opop_src = op_src->operations.first; - opop_dst; - opop_dst = opop_dst->next, opop_src = opop_src->next) - { - bke_override_property_operation_copy(opop_dst, opop_src); - } + op_dst->rna_path = BLI_strdup(op_src->rna_path); + BLI_duplicatelist(&op_dst->operations, &op_src->operations); + + for (IDOverrideStaticPropertyOperation *opop_dst = op_dst->operations.first, + *opop_src = op_src->operations.first; + opop_dst; + opop_dst = opop_dst->next, opop_src = opop_src->next) { + bke_override_property_operation_copy(opop_dst, opop_src); + } } void bke_override_property_clear(IDOverrideStaticProperty *op) { - BLI_assert(op->rna_path != NULL); + BLI_assert(op->rna_path != NULL); - MEM_freeN(op->rna_path); + MEM_freeN(op->rna_path); - for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) { - bke_override_property_operation_clear(opop); - } - BLI_freelistN(&op->operations); + for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) { + bke_override_property_operation_clear(opop); + } + BLI_freelistN(&op->operations); } /** * Remove and free given \a override_property from given ID \a override. */ -void BKE_override_static_property_delete(IDOverrideStatic *override, IDOverrideStaticProperty *override_property) +void BKE_override_static_property_delete(IDOverrideStatic *override, + IDOverrideStaticProperty *override_property) { - bke_override_property_clear(override_property); - BLI_freelinkN(&override->properties, override_property); + bke_override_property_clear(override_property); + BLI_freelinkN(&override->properties, override_property); } /** * Find override property operation from given sub-item(s), if it exists. */ IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_find( - IDOverrideStaticProperty *override_property, - const char *subitem_refname, const char *subitem_locname, - const int subitem_refindex, const int subitem_locindex, const bool strict, bool *r_strict) + IDOverrideStaticProperty *override_property, + const char *subitem_refname, + const char *subitem_locname, + const int subitem_refindex, + const int subitem_locindex, + const bool strict, + bool *r_strict) { - IDOverrideStaticPropertyOperation *opop; - const int subitem_defindex = -1; - - if (r_strict) { - *r_strict = true; - } - - if (subitem_locname != NULL) { - opop = BLI_findstring_ptr(&override_property->operations, subitem_locname, - offsetof(IDOverrideStaticPropertyOperation, subitem_local_name)); - - if (opop == NULL) { - return NULL; - } - - if (subitem_refname == NULL || opop->subitem_reference_name == NULL) { - return subitem_refname == opop->subitem_reference_name ? opop : NULL; - } - return (subitem_refname != NULL && opop->subitem_reference_name != NULL && - STREQ(subitem_refname, opop->subitem_reference_name)) ? opop : NULL; - } - - if (subitem_refname != NULL) { - opop = BLI_findstring_ptr(&override_property->operations, subitem_refname, - offsetof(IDOverrideStaticPropertyOperation, subitem_reference_name)); - - if (opop == NULL) { - return NULL; - } - - if (subitem_locname == NULL || opop->subitem_local_name == NULL) { - return subitem_locname == opop->subitem_local_name ? opop : NULL; - } - return (subitem_locname != NULL && opop->subitem_local_name != NULL && - STREQ(subitem_locname, opop->subitem_local_name)) ? opop : NULL; - } - - if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_locindex, sizeof(subitem_locindex), - offsetof(IDOverrideStaticPropertyOperation, subitem_local_index)))) - { - return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : NULL; - } - - if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_refindex, sizeof(subitem_refindex), - offsetof(IDOverrideStaticPropertyOperation, subitem_reference_index)))) - { - return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL; - } - - /* index == -1 means all indices, that is valid fallback in case we requested specific index. */ - if (!strict && (subitem_locindex != subitem_defindex) && - (opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_defindex, sizeof(subitem_defindex), - offsetof(IDOverrideStaticPropertyOperation, subitem_local_index)))) - { - if (r_strict) { - *r_strict = false; - } - return opop; - } - - return NULL; + IDOverrideStaticPropertyOperation *opop; + const int subitem_defindex = -1; + + if (r_strict) { + *r_strict = true; + } + + if (subitem_locname != NULL) { + opop = BLI_findstring_ptr(&override_property->operations, + subitem_locname, + offsetof(IDOverrideStaticPropertyOperation, subitem_local_name)); + + if (opop == NULL) { + return NULL; + } + + if (subitem_refname == NULL || opop->subitem_reference_name == NULL) { + return subitem_refname == opop->subitem_reference_name ? opop : NULL; + } + return (subitem_refname != NULL && opop->subitem_reference_name != NULL && + STREQ(subitem_refname, opop->subitem_reference_name)) ? + opop : + NULL; + } + + if (subitem_refname != NULL) { + opop = BLI_findstring_ptr(&override_property->operations, + subitem_refname, + offsetof(IDOverrideStaticPropertyOperation, subitem_reference_name)); + + if (opop == NULL) { + return NULL; + } + + if (subitem_locname == NULL || opop->subitem_local_name == NULL) { + return subitem_locname == opop->subitem_local_name ? opop : NULL; + } + return (subitem_locname != NULL && opop->subitem_local_name != NULL && + STREQ(subitem_locname, opop->subitem_local_name)) ? + opop : + NULL; + } + + if ((opop = BLI_listbase_bytes_find( + &override_property->operations, + &subitem_locindex, + sizeof(subitem_locindex), + offsetof(IDOverrideStaticPropertyOperation, subitem_local_index)))) { + return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : NULL; + } + + if ((opop = BLI_listbase_bytes_find( + &override_property->operations, + &subitem_refindex, + sizeof(subitem_refindex), + offsetof(IDOverrideStaticPropertyOperation, subitem_reference_index)))) { + return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL; + } + + /* index == -1 means all indices, that is valid fallback in case we requested specific index. */ + if (!strict && (subitem_locindex != subitem_defindex) && + (opop = BLI_listbase_bytes_find( + &override_property->operations, + &subitem_defindex, + sizeof(subitem_defindex), + offsetof(IDOverrideStaticPropertyOperation, subitem_local_index)))) { + if (r_strict) { + *r_strict = false; + } + return opop; + } + + return NULL; } /** * Find override property operation from given sub-item(s), or create it if it does not exist. */ IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_get( - IDOverrideStaticProperty *override_property, const short operation, - const char *subitem_refname, const char *subitem_locname, - const int subitem_refindex, const int subitem_locindex, - const bool strict, bool *r_strict, bool *r_created) + IDOverrideStaticProperty *override_property, + const short operation, + const char *subitem_refname, + const char *subitem_locname, + const int subitem_refindex, + const int subitem_locindex, + const bool strict, + bool *r_strict, + bool *r_created) { - IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find(override_property, - subitem_refname, subitem_locname, - subitem_refindex, subitem_locindex, - strict, r_strict); - - if (opop == NULL) { - opop = MEM_callocN(sizeof(IDOverrideStaticPropertyOperation), __func__); - opop->operation = operation; - if (subitem_locname) { - opop->subitem_local_name = BLI_strdup(subitem_locname); - } - if (subitem_refname) { - opop->subitem_reference_name = BLI_strdup(subitem_refname); - } - opop->subitem_local_index = subitem_locindex; - opop->subitem_reference_index = subitem_refindex; - - BLI_addtail(&override_property->operations, opop); - - if (r_created) { - *r_created = true; - } - } - else if (r_created) { - *r_created = false; - } - - return opop; + IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find( + override_property, + subitem_refname, + subitem_locname, + subitem_refindex, + subitem_locindex, + strict, + r_strict); + + if (opop == NULL) { + opop = MEM_callocN(sizeof(IDOverrideStaticPropertyOperation), __func__); + opop->operation = operation; + if (subitem_locname) { + opop->subitem_local_name = BLI_strdup(subitem_locname); + } + if (subitem_refname) { + opop->subitem_reference_name = BLI_strdup(subitem_refname); + } + opop->subitem_local_index = subitem_locindex; + opop->subitem_reference_index = subitem_refindex; + + BLI_addtail(&override_property->operations, opop); + + if (r_created) { + *r_created = true; + } + } + else if (r_created) { + *r_created = false; + } + + return opop; } -void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src) +void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, + IDOverrideStaticPropertyOperation *opop_src) { - if (opop_src->subitem_reference_name) { - opop_dst->subitem_reference_name = BLI_strdup(opop_src->subitem_reference_name); - } - if (opop_src->subitem_local_name) { - opop_dst->subitem_local_name = BLI_strdup(opop_src->subitem_local_name); - } + if (opop_src->subitem_reference_name) { + opop_dst->subitem_reference_name = BLI_strdup(opop_src->subitem_reference_name); + } + if (opop_src->subitem_local_name) { + opop_dst->subitem_local_name = BLI_strdup(opop_src->subitem_local_name); + } } void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop) { - if (opop->subitem_reference_name) { - MEM_freeN(opop->subitem_reference_name); - } - if (opop->subitem_local_name) { - MEM_freeN(opop->subitem_local_name); - } + if (opop->subitem_reference_name) { + MEM_freeN(opop->subitem_reference_name); + } + if (opop->subitem_local_name) { + MEM_freeN(opop->subitem_local_name); + } } /** * Remove and free given \a override_property_operation from given ID \a override_property. */ void BKE_override_static_property_operation_delete( - IDOverrideStaticProperty *override_property, IDOverrideStaticPropertyOperation *override_property_operation) + IDOverrideStaticProperty *override_property, + IDOverrideStaticPropertyOperation *override_property_operation) { - bke_override_property_operation_clear(override_property_operation); - BLI_freelinkN(&override_property->operations, override_property_operation); + bke_override_property_operation_clear(override_property_operation); + BLI_freelinkN(&override_property->operations, override_property_operation); } /** @@ -444,33 +484,36 @@ void BKE_override_static_property_operation_delete( * \return true if status is OK, false otherwise. */ bool BKE_override_static_status_check_local(Main *bmain, ID *local) { - BLI_assert(local->override_static != NULL); + BLI_assert(local->override_static != NULL); - ID *reference = local->override_static->reference; + ID *reference = local->override_static->reference; - if (reference == NULL) { - /* This is an override template, local status is always OK! */ - return true; - } + if (reference == NULL) { + /* This is an override template, local status is always OK! */ + return true; + } - BLI_assert(GS(local->name) == GS(reference->name)); + BLI_assert(GS(local->name) == GS(reference->name)); - /* Note that reference is assumed always valid, caller has to ensure that itself. */ + /* Note that reference is assumed always valid, caller has to ensure that itself. */ - PointerRNA rnaptr_local, rnaptr_reference; - RNA_id_pointer_create(local, &rnaptr_local); - RNA_id_pointer_create(reference, &rnaptr_reference); + PointerRNA rnaptr_local, rnaptr_reference; + RNA_id_pointer_create(local, &rnaptr_local); + RNA_id_pointer_create(reference, &rnaptr_reference); - if (!RNA_struct_override_matches( - bmain, - &rnaptr_local, &rnaptr_reference, NULL, local->override_static, - RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL)) - { - local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; - return false; - } + if (!RNA_struct_override_matches(bmain, + &rnaptr_local, + &rnaptr_reference, + NULL, + local->override_static, + RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | + RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, + NULL)) { + local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; + return false; + } - return true; + return true; } /** @@ -484,41 +527,43 @@ bool BKE_override_static_status_check_local(Main *bmain, ID *local) * \return true if status is OK, false otherwise. */ bool BKE_override_static_status_check_reference(Main *bmain, ID *local) { - BLI_assert(local->override_static != NULL); - - ID *reference = local->override_static->reference; - - if (reference == NULL) { - /* This is an override template, reference is virtual, so its status is always OK! */ - return true; - } - - BLI_assert(GS(local->name) == GS(reference->name)); - - if (reference->override_static && (reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) { - if (!BKE_override_static_status_check_reference(bmain, reference)) { - /* If reference is also override of another data-block, and its status is not OK, - * then this override is not OK either. - * Note that this should only happen when reloading libraries... */ - local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; - return false; - } - } - - PointerRNA rnaptr_local, rnaptr_reference; - RNA_id_pointer_create(local, &rnaptr_local); - RNA_id_pointer_create(reference, &rnaptr_reference); - - if (!RNA_struct_override_matches( - bmain, - &rnaptr_local, &rnaptr_reference, NULL, local->override_static, - RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL)) - { - local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; - return false; - } - - return true; + BLI_assert(local->override_static != NULL); + + ID *reference = local->override_static->reference; + + if (reference == NULL) { + /* This is an override template, reference is virtual, so its status is always OK! */ + return true; + } + + BLI_assert(GS(local->name) == GS(reference->name)); + + if (reference->override_static && (reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) { + if (!BKE_override_static_status_check_reference(bmain, reference)) { + /* If reference is also override of another data-block, and its status is not OK, + * then this override is not OK either. + * Note that this should only happen when reloading libraries... */ + local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; + return false; + } + } + + PointerRNA rnaptr_local, rnaptr_reference; + RNA_id_pointer_create(local, &rnaptr_local); + RNA_id_pointer_create(reference, &rnaptr_reference); + + if (!RNA_struct_override_matches(bmain, + &rnaptr_local, + &rnaptr_reference, + NULL, + local->override_static, + RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, + NULL)) { + local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; + return false; + } + + return true; } /** @@ -535,132 +580,138 @@ bool BKE_override_static_status_check_reference(Main *bmain, ID *local) * \return true if new overriding op was created, or some local data was reset. */ bool BKE_override_static_operations_create(Main *bmain, ID *local, const bool force_auto) { - BLI_assert(local->override_static != NULL); - const bool is_template = (local->override_static->reference == NULL); - bool ret = false; - - if (!is_template && (force_auto || local->override_static->flag & STATICOVERRIDE_AUTO)) { - PointerRNA rnaptr_local, rnaptr_reference; - RNA_id_pointer_create(local, &rnaptr_local); - RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference); - - eRNAOverrideMatchResult report_flags = 0; - RNA_struct_override_matches( - bmain, - &rnaptr_local, &rnaptr_reference, NULL, local->override_static, - RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE, &report_flags); - if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) { - ret = true; - } + BLI_assert(local->override_static != NULL); + const bool is_template = (local->override_static->reference == NULL); + bool ret = false; + + if (!is_template && (force_auto || local->override_static->flag & STATICOVERRIDE_AUTO)) { + PointerRNA rnaptr_local, rnaptr_reference; + RNA_id_pointer_create(local, &rnaptr_local); + RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference); + + eRNAOverrideMatchResult report_flags = 0; + RNA_struct_override_matches(bmain, + &rnaptr_local, + &rnaptr_reference, + NULL, + local->override_static, + RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE, + &report_flags); + if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) { + ret = true; + } #ifndef NDEBUG - if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) { - printf("We did restore some properties of %s from its reference.\n", local->name); - } - if (ret) { - printf("We did generate static override rules for %s\n", local->name); - } - else { - printf("No new static override rules for %s\n", local->name); - } + if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) { + printf("We did restore some properties of %s from its reference.\n", local->name); + } + if (ret) { + printf("We did generate static override rules for %s\n", local->name); + } + else { + printf("No new static override rules for %s\n", local->name); + } #endif - } - return ret; + } + return ret; } /** Check all overrides from given \a bmain and create/update overriding operations as needed. */ void BKE_main_override_static_operations_create(Main *bmain, const bool force_auto) { - ID *id; - - FOREACH_MAIN_ID_BEGIN(bmain, id) - { - if (force_auto || - (ID_IS_STATIC_OVERRIDE_AUTO(id) && (id->tag & LIB_TAG_OVERRIDESTATIC_AUTOREFRESH))) - { - BKE_override_static_operations_create(bmain, id, force_auto); - id->tag &= ~LIB_TAG_OVERRIDESTATIC_AUTOREFRESH; - } - } - FOREACH_MAIN_ID_END; + ID *id; + + FOREACH_MAIN_ID_BEGIN(bmain, id) + { + if (force_auto || + (ID_IS_STATIC_OVERRIDE_AUTO(id) && (id->tag & LIB_TAG_OVERRIDESTATIC_AUTOREFRESH))) { + BKE_override_static_operations_create(bmain, id, force_auto); + id->tag &= ~LIB_TAG_OVERRIDESTATIC_AUTOREFRESH; + } + } + FOREACH_MAIN_ID_END; } /** Update given override from its reference (re-applying overridden properties). */ void BKE_override_static_update(Main *bmain, ID *local) { - if (local->override_static == NULL || local->override_static->reference == NULL) { - return; - } - - /* Recursively do 'ancestors' overrides first, if any. */ - if (local->override_static->reference->override_static && (local->override_static->reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) { - BKE_override_static_update(bmain, local->override_static->reference); - } - - /* We want to avoid having to remap here, however creating up-to-date override is much simpler if based - * on reference than on current override. - * So we work on temp copy of reference, and 'swap' its content with local. */ - - /* XXX We need a way to get off-Main copies of IDs (similar to localized mats/texts/ etc.)! - * However, this is whole bunch of code work in itself, so for now plain stupid ID copy will do, - * as innefficient as it is. :/ - * Actually, maybe not! Since we are swapping with original ID's local content, we want to keep - * usercount in correct state when freeing tmp_id (and that usercounts of IDs used by 'new' local data - * also remain correct). */ - /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code). - * Not impossible to do, but would rather see first if extra useless usual user handling is actually - * a (performances) issue here. */ - - ID *tmp_id; - BKE_id_copy(bmain, local->override_static->reference, &tmp_id); - - if (tmp_id == NULL) { - return; - } - - PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL; - RNA_id_pointer_create(local, &rnaptr_src); - RNA_id_pointer_create(tmp_id, &rnaptr_dst); - if (local->override_static->storage) { - rnaptr_storage = &rnaptr_storage_stack; - RNA_id_pointer_create(local->override_static->storage, rnaptr_storage); - } - - RNA_struct_override_apply(bmain, &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. */ - BKE_id_swap(bmain, local, tmp_id); - - /* Again, horribly innefficient in our case, we need something off-Main (aka moar generic nolib copy/free stuff)! */ - /* XXX And crashing in complex cases (e.g. because depsgraph uses same data...). */ - BKE_id_free_ex(bmain, tmp_id, LIB_ID_FREE_NO_UI_USER, true); - - if (local->override_static->storage) { - /* We know this datablock is not used anywhere besides local->override->storage. */ - /* XXX For until we get fully shadow copies, we still need to ensure storage releases - * its usage of any ID pointers it may have. */ - BKE_id_free_ex(bmain, local->override_static->storage, LIB_ID_FREE_NO_UI_USER, true); - local->override_static->storage = NULL; - } - - local->tag |= LIB_TAG_OVERRIDESTATIC_REFOK; - - /* Full rebuild of Depsgraph! */ - DEG_on_visible_update(bmain, true); /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */ + if (local->override_static == NULL || local->override_static->reference == NULL) { + return; + } + + /* Recursively do 'ancestors' overrides first, if any. */ + if (local->override_static->reference->override_static && + (local->override_static->reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) { + BKE_override_static_update(bmain, local->override_static->reference); + } + + /* We want to avoid having to remap here, however creating up-to-date override is much simpler if based + * on reference than on current override. + * So we work on temp copy of reference, and 'swap' its content with local. */ + + /* XXX We need a way to get off-Main copies of IDs (similar to localized mats/texts/ etc.)! + * However, this is whole bunch of code work in itself, so for now plain stupid ID copy will do, + * as innefficient as it is. :/ + * Actually, maybe not! Since we are swapping with original ID's local content, we want to keep + * usercount in correct state when freeing tmp_id (and that usercounts of IDs used by 'new' local data + * also remain correct). */ + /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code). + * Not impossible to do, but would rather see first if extra useless usual user handling is actually + * a (performances) issue here. */ + + ID *tmp_id; + BKE_id_copy(bmain, local->override_static->reference, &tmp_id); + + if (tmp_id == NULL) { + return; + } + + PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL; + RNA_id_pointer_create(local, &rnaptr_src); + RNA_id_pointer_create(tmp_id, &rnaptr_dst); + if (local->override_static->storage) { + rnaptr_storage = &rnaptr_storage_stack; + RNA_id_pointer_create(local->override_static->storage, rnaptr_storage); + } + + RNA_struct_override_apply( + bmain, &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. */ + BKE_id_swap(bmain, local, tmp_id); + + /* Again, horribly innefficient in our case, we need something off-Main (aka moar generic nolib copy/free stuff)! */ + /* XXX And crashing in complex cases (e.g. because depsgraph uses same data...). */ + BKE_id_free_ex(bmain, tmp_id, LIB_ID_FREE_NO_UI_USER, true); + + if (local->override_static->storage) { + /* We know this datablock is not used anywhere besides local->override->storage. */ + /* XXX For until we get fully shadow copies, we still need to ensure storage releases + * its usage of any ID pointers it may have. */ + BKE_id_free_ex(bmain, local->override_static->storage, LIB_ID_FREE_NO_UI_USER, true); + local->override_static->storage = NULL; + } + + local->tag |= LIB_TAG_OVERRIDESTATIC_REFOK; + + /* Full rebuild of Depsgraph! */ + DEG_on_visible_update( + bmain, + true); /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */ } /** Update all overrides from given \a bmain. */ void BKE_main_override_static_update(Main *bmain) { - ID *id; - - FOREACH_MAIN_ID_BEGIN(bmain, id) - { - if (id->override_static != NULL && id->lib == NULL) { - BKE_override_static_update(bmain, id); - } - } - FOREACH_MAIN_ID_END; + ID *id; + + FOREACH_MAIN_ID_BEGIN(bmain, id) + { + if (id->override_static != NULL && id->lib == NULL) { + BKE_override_static_update(bmain, id); + } + } + FOREACH_MAIN_ID_END; } /*********************************************************************************************************************** @@ -680,82 +731,84 @@ void BKE_main_override_static_update(Main *bmain) /** Initialize an override storage. */ OverrideStaticStorage *BKE_override_static_operations_store_initialize(void) { - return BKE_main_new(); + return BKE_main_new(); } /** * Generate suitable 'write' data (this only affects differential override operations). * * Note that \a local ID is no more modified by this call, all extra data are stored in its temp \a storage_id copy. */ -ID *BKE_override_static_operations_store_start(Main *bmain, OverrideStaticStorage *override_storage, ID *local) +ID *BKE_override_static_operations_store_start(Main *bmain, + OverrideStaticStorage *override_storage, + ID *local) { - BLI_assert(local->override_static != NULL); - BLI_assert(override_storage != NULL); - const bool is_template = (local->override_static->reference == NULL); + BLI_assert(local->override_static != NULL); + BLI_assert(override_storage != NULL); + const bool is_template = (local->override_static->reference == NULL); - if (is_template) { - /* This is actually purely local data with an override template, nothing to do here! */ - return NULL; - } + if (is_template) { + /* This is actually purely local data with an override template, nothing to do here! */ + return NULL; + } - /* Forcefully ensure we know about all needed override operations. */ - BKE_override_static_operations_create(bmain, local, false); + /* Forcefully ensure we know about all needed override operations. */ + BKE_override_static_operations_create(bmain, local, false); - ID *storage_id; + ID *storage_id; #ifdef DEBUG_OVERRIDE_TIMEIT - TIMEIT_START_AVERAGED(BKE_override_operations_store_start); + TIMEIT_START_AVERAGED(BKE_override_operations_store_start); #endif - /* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy never-overridable - * data (like Mesh geometry etc.)? And also maybe avoid lib refcounting completely (shallow copy...). */ - /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code). - * Not impossible to do, but would rather see first is extra useless usual user handling is actually - * a (performances) issue here, before doing it. */ - BKE_id_copy((Main *)override_storage, local, &storage_id); - - if (storage_id != NULL) { - PointerRNA rnaptr_reference, rnaptr_final, rnaptr_storage; - RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference); - RNA_id_pointer_create(local, &rnaptr_final); - RNA_id_pointer_create(storage_id, &rnaptr_storage); - - if (!RNA_struct_override_store( - bmain, &rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_static)) - { - BKE_id_free_ex(override_storage, storage_id, LIB_ID_FREE_NO_UI_USER, true); - storage_id = NULL; - } - } - - local->override_static->storage = storage_id; + /* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy never-overridable + * data (like Mesh geometry etc.)? And also maybe avoid lib refcounting completely (shallow copy...). */ + /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code). + * Not impossible to do, but would rather see first is extra useless usual user handling is actually + * a (performances) issue here, before doing it. */ + BKE_id_copy((Main *)override_storage, local, &storage_id); + + if (storage_id != NULL) { + PointerRNA rnaptr_reference, rnaptr_final, rnaptr_storage; + RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference); + RNA_id_pointer_create(local, &rnaptr_final); + RNA_id_pointer_create(storage_id, &rnaptr_storage); + + if (!RNA_struct_override_store( + bmain, &rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_static)) { + BKE_id_free_ex(override_storage, storage_id, LIB_ID_FREE_NO_UI_USER, true); + storage_id = NULL; + } + } + + local->override_static->storage = storage_id; #ifdef DEBUG_OVERRIDE_TIMEIT - TIMEIT_END_AVERAGED(BKE_override_operations_store_start); + TIMEIT_END_AVERAGED(BKE_override_operations_store_start); #endif - return storage_id; + return storage_id; } /** Restore given ID modified by \a BKE_override_operations_store_start, to its original state. */ -void BKE_override_static_operations_store_end(OverrideStaticStorage *UNUSED(override_storage), ID *local) +void BKE_override_static_operations_store_end(OverrideStaticStorage *UNUSED(override_storage), + ID *local) { - BLI_assert(local->override_static != NULL); + BLI_assert(local->override_static != NULL); - /* Nothing else to do here really, we need to keep all temp override storage data-blocks in memory until - * whole file is written anyway (otherwise we'd get mem pointers overlap...). */ - local->override_static->storage = NULL; + /* Nothing else to do here really, we need to keep all temp override storage data-blocks in memory until + * whole file is written anyway (otherwise we'd get mem pointers overlap...). */ + local->override_static->storage = NULL; } void BKE_override_static_operations_store_finalize(OverrideStaticStorage *override_storage) { - /* We cannot just call BKE_main_free(override_storage), not until we have option to make 'ghost' copies of IDs - * without increasing usercount of used data-blocks... */ - ID *id; + /* We cannot just call BKE_main_free(override_storage), not until we have option to make 'ghost' copies of IDs + * without increasing usercount of used data-blocks... */ + ID *id; - FOREACH_MAIN_ID_BEGIN(override_storage, id) - { - BKE_id_free_ex(override_storage, id, LIB_ID_FREE_NO_UI_USER, true); - } - FOREACH_MAIN_ID_END; + FOREACH_MAIN_ID_BEGIN(override_storage, id) + { + BKE_id_free_ex(override_storage, id, LIB_ID_FREE_NO_UI_USER, true); + } + FOREACH_MAIN_ID_END; - BKE_main_free(override_storage); + BKE_main_free(override_storage); } |