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
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/lib_override.c')
-rw-r--r--source/blender/blenkernel/intern/lib_override.c278
1 files changed, 227 insertions, 51 deletions
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 702d718f2b9..7a6e7a35724 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -217,6 +217,32 @@ static ID *lib_override_library_create_from(Main *bmain, ID *reference_id)
return local_id;
}
+/** Check if given ID has some override rules that actually indicate the user edited it.
+ *
+ * TODO: This could be simplified by storing a flag in IDOverrideLibrary during the diffing
+ * process? */
+bool BKE_lib_override_library_is_user_edited(struct ID *id)
+{
+ if (!ID_IS_OVERRIDE_LIBRARY(id)) {
+ return false;
+ }
+
+ LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
+ LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ if ((opop->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) != 0) {
+ continue;
+ }
+ if (opop->operation == IDOVERRIDE_LIBRARY_OP_NOOP) {
+ continue;
+ }
+ /* If an operation does not match the filters above, it is considered as a user-editing one,
+ * therefore this override is user-edited. */
+ return true;
+ }
+ }
+ return false;
+}
+
/** Create an overridden local copy of linked reference. */
ID *BKE_lib_override_library_create_from_id(Main *bmain,
ID *reference_id,
@@ -383,7 +409,7 @@ typedef struct LibOverrideGroupTagData {
*
* Requires existing `Main.relations`.
*
- * Note: this is typically called to complete `lib_override_linked_group_tag()`.
+ * NOTE: This is typically called to complete `lib_override_linked_group_tag()`.
*/
static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTagData *data)
{
@@ -624,53 +650,59 @@ static void lib_override_library_create_post_process(
{
BKE_main_collection_sync(bmain);
- switch (GS(id_root->name)) {
- case ID_GR: {
- Object *ob_reference = id_reference != NULL && GS(id_reference->name) == ID_OB ?
- (Object *)id_reference :
- NULL;
- Collection *collection_new = ((Collection *)id_root->newid);
- if (ob_reference != NULL) {
- BKE_collection_add_from_object(bmain, scene, ob_reference, collection_new);
- }
- else if (id_reference != NULL) {
- BKE_collection_add_from_collection(
- bmain, scene, ((Collection *)id_reference), collection_new);
- }
- else {
- BKE_collection_add_from_collection(bmain, scene, ((Collection *)id_root), collection_new);
- }
+ if (id_root->newid != NULL) {
+ switch (GS(id_root->name)) {
+ case ID_GR: {
+ Object *ob_reference = id_reference != NULL && GS(id_reference->name) == ID_OB ?
+ (Object *)id_reference :
+ NULL;
+ Collection *collection_new = ((Collection *)id_root->newid);
+ if (ob_reference != NULL) {
+ BKE_collection_add_from_object(bmain, scene, ob_reference, collection_new);
+ }
+ else if (id_reference != NULL) {
+ BLI_assert(GS(id_reference->name) == ID_GR);
+ BKE_collection_add_from_collection(
+ bmain, scene, ((Collection *)id_reference), collection_new);
+ }
+ else {
+ BKE_collection_add_from_collection(
+ bmain, scene, ((Collection *)id_root), collection_new);
+ }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection_new, ob_new) {
- if (ob_new != NULL && ob_new->id.override_library != NULL) {
- if (ob_reference != NULL) {
- Base *base;
- if ((base = BKE_view_layer_base_find(view_layer, ob_new)) == NULL) {
- BKE_collection_object_add_from(bmain, scene, ob_reference, ob_new);
- base = BKE_view_layer_base_find(view_layer, ob_new);
- DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
- }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection_new, ob_new) {
+ if (ob_new != NULL && ob_new->id.override_library != NULL) {
+ if (ob_reference != NULL) {
+ Base *base;
+ if ((base = BKE_view_layer_base_find(view_layer, ob_new)) == NULL) {
+ BKE_collection_object_add_from(bmain, scene, ob_reference, ob_new);
+ base = BKE_view_layer_base_find(view_layer, ob_new);
+ DEG_id_tag_update_ex(
+ bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
+ }
- if (ob_new == (Object *)ob_reference->id.newid) {
- /* TODO: is setting active needed? */
- BKE_view_layer_base_select_and_set_active(view_layer, base);
+ if (ob_new == (Object *)ob_reference->id.newid) {
+ /* TODO: is setting active needed? */
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
+ }
+ }
+ else if (BKE_view_layer_base_find(view_layer, ob_new) == NULL) {
+ BKE_collection_object_add(bmain, collection_new, ob_new);
+ DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
}
- }
- else if (BKE_view_layer_base_find(view_layer, ob_new) == NULL) {
- BKE_collection_object_add(bmain, collection_new, ob_new);
- DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ break;
}
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- break;
- }
- case ID_OB: {
- BKE_collection_object_add_from(bmain, scene, (Object *)id_root, ((Object *)id_root->newid));
- break;
+ case ID_OB: {
+ BKE_collection_object_add_from(
+ bmain, scene, (Object *)id_root, ((Object *)id_root->newid));
+ break;
+ }
+ default:
+ break;
}
- default:
- break;
}
/* We need to ensure all new overrides of objects are properly instantiated. */
@@ -803,7 +835,8 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain,
* \param id_root: The root liboverride ID to resync from.
* \return true if override was successfully resynced.
*/
-bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_root)
+bool BKE_lib_override_library_resync(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_root, const bool do_hierarchy_enforce)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
@@ -883,6 +916,8 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
ID *id_override_new = id->newid;
ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
+ BLI_assert((id_override_new->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0);
+
if (id_override_old != NULL) {
/* Swap the names between old override ID and new one. */
char id_name_buf[MAX_ID_NAME];
@@ -950,8 +985,14 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
}
}
- RNA_struct_override_apply(
- bmain, &rnaptr_dst, &rnaptr_src, NULL, id_override_new->override_library);
+ RNA_struct_override_apply(bmain,
+ &rnaptr_dst,
+ &rnaptr_src,
+ NULL,
+ id_override_new->override_library,
+ do_hierarchy_enforce ?
+ RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS :
+ RNA_OVERRIDE_APPLY_FLAG_NOP);
}
}
}
@@ -975,11 +1016,21 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
}
id->tag &= ~LIB_TAG_DOIT;
}
- /* Also cleanup old overrides that went missing in new linked data. */
+ /* Also deal with old overrides that went missing in new linked data. */
else if (id->tag & LIB_TAG_MISSING && !ID_IS_LINKED(id)) {
BLI_assert(ID_IS_OVERRIDE_LIBRARY(id));
- id->tag |= LIB_TAG_DOIT;
- id->tag &= ~LIB_TAG_MISSING;
+ if (!BKE_lib_override_library_is_user_edited(id)) {
+ /* If user never edited them, we can delete them. */
+ id->tag |= LIB_TAG_DOIT;
+ id->tag &= ~LIB_TAG_MISSING;
+ CLOG_INFO(&LOG, 3, "Old override %s is being deleted", id->name);
+ }
+ else {
+ /* Otherwise, keep them, user needs to decide whether what to do with them. */
+ BLI_assert((id->tag & LIB_TAG_DOIT) == 0);
+ id_fake_user_set(id);
+ CLOG_INFO(&LOG, 3, "Old override %s is being kept around as it was user-edited", id->name);
+ }
}
}
FOREACH_MAIN_ID_END;
@@ -1007,6 +1058,119 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
}
/**
+ * Detect and handle required resync of overrides data, when relations between reference linked IDs
+ * have changed.
+ *
+ * This is a fairly complex and costly operation, typically it should be called after
+ * #BKE_lib_override_library_main_update, which would already detect and tag a lot of cases.
+ *
+ * This function will first detect the remaining cases requiring a resync (namely, either when an
+ * existing linked ID that did not require to be overridden before now would be, or when new IDs
+ * are added to the hierarchy).
+ *
+ * Then it will handle the resync of necessary IDs (through calls to
+ * #BKE_lib_override_library_resync).
+ */
+void BKE_lib_override_library_main_resync(Main *bmain, Scene *scene, ViewLayer *view_layer)
+{
+ BKE_main_relations_create(bmain, 0);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+
+ /* NOTE: in code below, the order in which `FOREACH_MAIN_ID_BEGIN` processes ID types ensures
+ * that we always process 'higher-level' overrides first (i.e. scenes, then collections, then
+ * objects, then other types). */
+
+ /* Detect all linked data that would need to be overridden if we had to create an override from
+ * those used by current existing overrides. */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ continue;
+ }
+ if (id->tag & (LIB_TAG_DOIT | LIB_TAG_MISSING)) {
+ /* We already processed that ID as part of another ID's hierarchy. */
+ continue;
+ }
+
+ LibOverrideGroupTagData data = {.bmain = bmain,
+ .id_root = id->override_library->reference,
+ .tag = LIB_TAG_DOIT,
+ .missing_tag = LIB_TAG_MISSING};
+ lib_override_linked_group_tag(&data);
+ BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
+ lib_override_hierarchy_dependencies_recursive_tag(&data);
+ BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
+ }
+ FOREACH_MAIN_ID_END;
+
+ /* Now check existing overrides, those needing resync will be the one either already tagged as
+ * such, or the one using linked data that is now tagged as needing override. */
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ continue;
+ }
+
+ if (id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) {
+ CLOG_INFO(&LOG, 4, "ID %s was already tagged as needing resync", id->name);
+ continue;
+ }
+
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
+ BLI_assert(entry != NULL);
+
+ for (MainIDRelationsEntryItem *entry_item = entry->to_ids; entry_item != NULL;
+ entry_item = entry_item->next) {
+ if (entry_item->usage_flag &
+ (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
+ continue;
+ }
+ ID *id_to = *entry_item->id_pointer.to;
+
+ /* Case where this ID pointer was to a linked ID, that now needs to be overridden. */
+ if (ID_IS_LINKED(id_to) && (id_to->tag & LIB_TAG_DOIT) != 0) {
+ id->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
+ CLOG_INFO(&LOG,
+ 3,
+ "ID %s now tagged as needing resync because they use linked %s that now needs "
+ "to be overridden",
+ id->name,
+ id_to->name);
+ break;
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
+
+ BKE_main_relations_free(bmain);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+
+ /* And do the actual resync for all IDs detected as needing it.
+ * NOTE: Since this changes `bmain` (adding **and** removing IDs), we cannot use
+ * `FOREACH_MAIN_ID_BEGIN/END` here, and need special multi-loop processing. */
+ bool do_continue = true;
+ while (do_continue) {
+ ListBase *lb;
+ do_continue = false;
+ FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
+ FOREACH_MAIN_LISTBASE_ID_BEGIN (lb, id) {
+ if ((id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0) {
+ continue;
+ }
+ do_continue = true;
+ const bool success = BKE_lib_override_library_resync(bmain, scene, view_layer, id, false);
+ CLOG_INFO(&LOG, 2, "Resynced %s, success: %d", id->name, success);
+ break;
+ }
+ FOREACH_MAIN_LISTBASE_ID_END;
+ if (do_continue) {
+ break;
+ }
+ }
+ FOREACH_MAIN_LISTBASE_END;
+ }
+}
+
+/**
* Advanced 'smart' function to delete library overrides (including their existing override
* hierarchy) and remap their usages to their linked reference IDs.
*
@@ -1882,6 +2046,14 @@ void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain)
FOREACH_MAIN_ID_END;
}
+static void lib_override_id_swap(Main *bmain, ID *id_local, ID *id_temp)
+{
+ BKE_lib_id_swap(bmain, id_local, id_temp);
+ /* We need to keep these tags from temp ID into orig one.
+ * ID swap does not swap most of ID data itself. */
+ id_local->tag |= (id_temp->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC);
+}
+
/** Update given override from its reference (re-applying overridden properties). */
void BKE_lib_override_library_update(Main *bmain, ID *local)
{
@@ -1945,16 +2117,20 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
RNA_id_pointer_create(local->override_library->storage, rnaptr_storage);
}
- RNA_struct_override_apply(
- bmain, &rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_library);
+ RNA_struct_override_apply(bmain,
+ &rnaptr_dst,
+ &rnaptr_src,
+ rnaptr_storage,
+ local->override_library,
+ RNA_OVERRIDE_APPLY_FLAG_NOP);
/* 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_lib_id_swap(bmain, local, tmp_id);
+ lib_override_id_swap(bmain, local, tmp_id);
if (local_key != NULL && tmp_key != NULL) {
/* This is some kind of hard-coded 'always enforced override'. */
- BKE_lib_id_swap(bmain, &local_key->id, &tmp_key->id);
+ lib_override_id_swap(bmain, &local_key->id, &tmp_key->id);
tmp_key->id.flag |= (local_key->id.flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE);
/* The swap of local and tmp_id inverted those pointers, we need to redefine proper
* relationships. */